NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
PyPI · #3468 most downloaded on PyPI
Declarative parameters for robust Python classes and a rich API for reactive programming
Last release 9 days ago
25 Sep 2026
Release timing varies
gaps range from 8 days to 3 months
Nearly every release is documented
notes for 42 of 45 stable releases
Nothing withdrawn
no release was ever pulled
14 years old
133 releases · first in 2012
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
One column per quarter.
This patch release fixes a cluster of bugs in async rx pipelines (stale value propagation, cancellation leaks, branching, invalidation finalizers, and
This patch release fixes a cluster of bugs in async rx pipelines (stale value propagation, cancellation leaks, branching, invalidation finalizers, and an unhandled exception in async operations), plus a memory leak on short-lived reactive pipelines, a thread-safety issue in the Parameter init cache, and a List item_type validation bug rejecting subclasses with a custom metaclass.
Many thanks to @philippjfr, @hoxbro, @maximlt, @s-t-e-v-e-n-k and @Coderambling for their contributions to this release.
List item_type validation rejecting subclasses with a custom metaclass (#1166)os.path.commonpath to fix FileSelector path abbreviation splitting on partial path components (#1165)rx from propagating a stale value while an async node is awaiting (#1173)rx invalidation finalizer keeping its own node alive (#1174)rx node (#1178)rx operation (#1179)async_executor leaking an event loop per call and leaking cancellations (#1180)Nothing published for this version
Nothing published for this version
Nothing published for this version
This patch release adds a mypy plugin to handle the descriptor __set__ type narrowing issue, reorders param.List overloads to allow default type infer
This patch release adds a mypy plugin to handle the descriptor __set__ type narrowing issue, reorders param.List overloads to allow default type inference, and fixes the conda build.
Many thanks to @philippjfr and @hoxbro for their contributions to this release.
__set__ issue (#1148)param.List overloads to allow default type inference (#1149)Nothing published for this version
Nothing published for this version
Param 2.4.0 brings first-class static typing support to the entire Param ecosystem — all major parameter types now carry precise type information that
Param 2.4.0 brings first-class static typing support to the entire Param ecosystem — all major parameter types now carry precise type information that flows through to your IDE and type checker, with types inferred directly from your existing parameter declarations. The release also adds a lazy mode to reactive expressions (rx) and includes performance optimizations that speed up parameter initialization in large class hierarchies.
Many thanks to @philippjfr, @hoxbro and @camriddell for their contributions to this release.
Parameter generics (Parameter[_T]) and add typed overloads for all major Parameter subclasses and add typing for public APIs (#1066, #1112, #1130, #1131, #1132, #1134, #1136, #1137, #1141)py.typed PEP 561 marker so type checkers automatically recognize Param's inline annotations without requiring separate stubs (#1066)rx(..., lazy=) argument (#1106)Parameter initialization (#1124)Parameter instantiation (#1122)__copy__ for Parameter to speed up instance Parameter creation (#1128)re.search for param.String regex check (#1142)Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
This patch release fixes an issue where rx pipelines with shared provenance would not use a shared cache, resulting in unnecessary re-evaluation of sh
This patch release fixes an issue where rx pipelines with shared provenance would not use a shared cache, resulting in unnecessary re-evaluation of shared inputs.
Fixes:
rx inputs are reused (#1117)Date: 2026-03-31
This patch release fixes an issue where rx pipelines with shared provenance would not use a shared cache, resulting in unnecessary re-evaluation of shared inputs.
Fixes:
rx inputs are reused (#1117)Nothing published for this version
Nothing published for this version
This patch release fixes a regression introduced in Parameterized by adding a docstring to its __init__ method, shadowing user-defined class docstring
This patch release fixes a regression introduced in Parameterized by adding a docstring to its __init__ method, shadowing user-defined class docstrings displayed in IDEs like VSCode.
Fixes:
__init__ docstring as it shadows class user docstrings (#1104)Compatibility / Tests:
Nothing published for this version
Nothing published for this version
This patch release fixes a regression introduced in the param.parameterized.edit_constant context manager.
This patch release fixes a regression introduced in the param.parameterized.edit_constant context manager.
Fixes:
edit_constant to prevent class value mutation when not constantDate: 2025-11-25
This patch release fixes a regression introduced in the param.parameterized.edit_constant context manager.
Fixes:
edit_constant to prevent class value mutation when not constantNothing published for this version
All the docstrings have been improved thanks to a massive effort from @MarcSkovMadsen. Several deprecated APIs have now been removed, and the minimum…
This minor release brings a number of new features, enhancements, bug fixes, and documentation improvements. Notably, it introduces the new Parameter attributes default_factory and metadata, and the ParameterizedABC class to declare Parameterized abstract base classes. All the docstrings have been improved thanks to a massive effort from @MarcSkovMadsen. Several deprecated APIs have now been removed, and the minimum supported Python version has been bumped to 3.10. Many thanks to our new contributors @Azaya89, @Coderambling, and @ypsah, as well as to @MarcSkovMadsen, @hoxbro, @maximlt, @philippjfr, and all others for their continued maintenance and development efforts.
Features:
default_factory attribute to the base Parameter (#1092)metadata attribute to the base Parameter (#1094)ParameterizedABC => This approach should be favored over __abstract = True (#1031).rx.set() method (#957)Enhancements:
len() on a reactive expression (#1033)AttributeError when attempting to set the value attribute of a reactive expression (#1022)is_instance attribute to the List Parameter (#1023)depends(..., on_init=True) to be applied to async method (#1067)concrete keyword to the descendents function => Prefer concrete(<cls>, descendents=True) over concrete_descendents(<cls>) (#1027)Performance Enhancements:
Bug Fixes:
descendents on an object() instance (#1024)edit_constant resets class and instance level parameters (#1015)constant attribute is inherited (#1017)ParameterizedFunction.__init__ (#1039).values()/get_value_generator() dealing with Dynamic params and an updated default value (#1058)nested_refs when updating another ref (#1061)ReactiveESMMetaClass (#1064)reactive_ops.__call__ (#1069)unwatch no longer logs a warning and idempotent behavior clarified (#1018)SelectorBase (#1086)Documentation:
Breaking changes:
print_all_param_defaults function (#1029)| Warning | Description |
|---|---|
ParamFutureWarning since 2.2.0, ParamDeprecationWarning since 2.0.0 |
Parameter slots / List._class: use instead item_type |
ParamFutureWarning since 2.2.0, ParamDeprecationWarning since 2.0.0 |
Parameter slots / Number.set_hook: no replacement |
ParamFutureWarning since 2.2.0, ParamDeprecationWarning since 2.0.0 |
param.__init__ module / param.produce_value: no replacement |
ParamFutureWarning since 2.2.0, ParamDeprecationWarning since 2.0.0 |
param.__init__ module / param.as_unicode: no replacement |
ParamFutureWarning since 2.2.0, ParamDeprecationWarning since 2.0.0 |
param.__init__ module / param.is_ordered_dict: no replacement |
ParamFutureWarning since 2.2.0, ParamDeprecationWarning since 2.0.0 |
param.__init__ module / param.hashable: no replacement |
ParamFutureWarning since 2.2.0, ParamDeprecationWarning since 2.0.0 |
param.__init__ module / param.named_objs: no replacement |
ParamFutureWarning since 2.2.0, ParamDeprecationWarning since 2.0.0 |
param.__init__ module / param.normalize_path: no replacement |
ParamFutureWarning since 2.2.0, ParamDeprecationWarning since 2.0.0 |
param.__init__ module / param.abbreviate_paths: no replacement |
ParamFutureWarning since 2.2.0, ParamDeprecationWarning since 2.0.0 |
param.parameterized module / param.parameterized.all_equal: no replacement |
ParamFutureWarning since 2.2.0, ParamDeprecationWarning since 2.0.0 |
param.parameterized module / param.parameterized.add_metaclass: no replacement |
ParamFutureWarning since 2.2.0, ParamDeprecationWarning since 2.0.0 |
param.parameterized module / param.parameterized.batch_watch: use instead batch_call_watchers |
ParamFutureWarning since 2.2.0, ParamDeprecationWarning since 2.0.0 |
param.parameterized module / param.parameterized.recursive_repr: no replacement |
ParamFutureWarning since 2.2.0, ParamDeprecationWarning since 2.0.0 |
param.parameterized module / param.parameterized.overridable_property: no replacement |
ParamFutureWarning since 2.2.0, ParamDeprecationWarning since 2.0.0, soft-deprecated since 1.12.0 |
Parameterized .param namespace / .param.set_default: use instead for k,v in p.param.objects().items(): print(f"{p.__class__.name}.{k}={repr(v.default)} |
ParamFutureWarning since 2.2.0, ParamDeprecationWarning since 2.0.0, soft-deprecated since 1.12.0 |
Parameterized .param namespace / .param._add_parameter: use instead .param.add_parameter |
ParamFutureWarning since 2.2.0, ParamDeprecationWarning since 2.0.0, soft-deprecated since 1.12.0 |
Parameterized .param namespace / .param.params: use instead .param.values() or .param['param'] |
ParamFutureWarning since 2.2.0, ParamDeprecationWarning since 2.0.0, soft-deprecated since 1.12.0 |
Parameterized .param namespace / .param.set_param: use instead .param.update |
ParamFutureWarning since 2.2.0, ParamDeprecationWarning since 2.0.0, soft-deprecated since 1.12.0 |
Parameterized .param namespace / .param.get_param_values: use instead .param.values().items() (or .param.values() for the common case of dict(....param.get_param_values())) |
ParamFutureWarning since 2.2.0, ParamDeprecationWarning since 2.0.0, soft-deprecated since 1.12.0 |
Parameterized .param namespace / .param.params_depended_on: use instead .param.method_dependencies |
ParamFutureWarning since 2.2.0, ParamDeprecationWarning since 2.0.0, soft-deprecated since 1.12.0 |
Parameterized .param namespace / .param.defaults: use instead {k:v.default for k,v in p.param.objects().items()} |
ParamFutureWarning since 2.2.0, ParamDeprecationWarning since 2.0.0, soft-deprecated since 1.12.0 |
Parameterized .param namespace / .param.print_param_defaults: use instead for k,v in p.param.objects().items(): print(f"{p.__class__.name}.{k}={repr(v.default)}") |
ParamFutureWarning since 2.2.0, ParamDeprecationWarning since 2.0.0, soft-deprecated since 1.12.0 |
Parameterized .param namespace / .param.print_param_values: use instead for k,v in p.param.objects().items(): print(f"{p.__class__.name}.{k}={repr(v.default)}") |
ParamFutureWarning since 2.2.0, ParamDeprecationWarning since 2.0.0, soft-deprecated since 1.12.0 |
Parameterized .param namespace / .param.message: use instead .param.log(param.MESSAGE, ...) |
ParamFutureWarning since 2.2.0, ParamDeprecationWarning since 2.0.0, soft-deprecated since 1.12.0 |
Parameterized .param namespace / .param.verbose: use instead .param.log(param.VERBOSE, ...) |
ParamFutureWarning since 2.2.0, ParamDeprecationWarning since 2.0.0, soft-deprecated since 1.12.0 |
Parameterized .param namespace / .param.debug: use instead .param.log(param.DEBUG, ...) |
ParamFutureWarning since 2.2.0, ParamDeprecationWarning since 2.1.0, ParamPendingDeprecationWarning since 2.0.0 |
Instantiating most parameters with positional arguments beyond default is deprecated |
ParamFutureWarning since 2.2.0, ParamDeprecationWarning since 2.1.0, ParamPendingDeprecationWarning since 2.0.0 |
For Selector parameters that accept objects as first positional argument, and ClassSelector parameters that accept class_ as first positional argument, passing any argument by position is deprecated. |
Deprecations:
what of .param.watch_values() (#1073)pickle_default_value (#1019)version.py (#1002)compute_default_fn slot and compute_default() method (#1012)Compatibility:
Internal:
_find_stack_level() utility to emit warnings with the right stack level (#1083)Infrastructure / Tests:
Governance:
Contributor Experience:
setup-dev command (#1081)Nothing published for this version
Nothing published for this version
Nothing published for this version
This patch release contains a bug fix for nested references. Thanks to @philippjfr for their contribution.
This patch release contains a bug fix for nested references. Thanks to @philippjfr for their contribution.
Bug Fixes:
Date: 2025-06-11
This patch release contains a bug fix for nested references. Thanks to @philippjfr for their contribution.
Bug Fixes:
Nothing published for this version
This minor release brings a few enhancements and bugfixes. Importantly, it includes some breaking changes, removing deprecated APIs or raising errors…
This minor release brings a few enhancements and bugfixes. Importantly, it includes some breaking changes, removing deprecated APIs or raising errors during unsafe operations which would previously only emit warnings. Many thanks to @gandhis1 and @JRRudy1 for their first contributions, and to @hoxbro, @maximlt,and @MarcSkovMadsen for their continued maintenance and development efforts.
Enhancements:
depends and accept_arguments decorators (#962)gen_types decorator (#966)Bug Fixes:
super().__init_subclass__ call in _ParameterBase.__init_subclass__ (#969)_dict_update (#980)Documentation:
Breaking changes / Deprecations:
_param_watchers, raise RuntimeError on unsafe ops during init, and failed validation of a parameter default after inheritance (#973)Compatibility:
Infrastructure / Tests:
Nothing published for this version
Nothing published for this version
Nothing published for this version
This minor release contains bug fixes for reactive expressions and a few minor documentation improvements. Thanks to @jrycw for their first contributi
This minor release contains bug fixes for reactive expressions and a few minor documentation improvements. Thanks to @jrycw for their first contribution! And to @ahuang11, @maximlt, and @philippjfr for their continued maintenance and development efforts.
Bug fixes:
rx._callback resolves accessors (#949)instantiate=True (#938)Documentation:
Maintenance:
test_reactive_logic_unary_ops on Python 3.12 (#946)Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Passing positional arguments to Parameter now raises a ParamDeprecationWarning
This minor release focuses on improving reactive expressions and support for asynchronous (and synchronous) generators. Many thanks to @maximlt, @Hoxbro and @philippjfr for their continued maintenance and development efforts.
and_, bool, map, not_, or_ and updating (#906)rx (#917).rx.resolve (#918).rx.pipe (#924).param.update context manager restore refs (#915)rx leading to unnecessary evaluation (#919)Parameter now raises a ParamDeprecationWarning (#921)Nothing published for this version
Nothing published for this version
Nothing published for this version
This patch release fixes a few bugs and introduces a performance enhancement. Many thanks to @alfredocarella for their first contribution, and to the
This patch release fixes a few bugs and introduces a performance enhancement. Many thanks to @alfredocarella for their first contribution, and to the maintainers @maximlt and @philippjfr for contributing to this release.
Optimization:
Bug fixes:
iscoroutinefunction (#894)setuptools-scm<7 (#903)Documentation:
Nothing published for this version
This minor release fixes a number of bugs, including a regression introduced by the replacement of the build backend (setuptools for hatchling) which
This minor release fixes a number of bugs, including a regression introduced by the replacement of the build backend (setuptools for hatchling) which led to the doc folder being wrongly packaged. Many thanks to @SultanOrazbayev for their first contribution, to @musicinmybrain for spotting the regression and submitting fixes, and to the maintainers @Hoxbro, @jbednar and @maximlt for contributing to this release.
Bug fixes:
doc folder in site-packages (#878)feather-format test dependency (#879)tables to the tests-deser extra (#880)_state_push and _state_pop (#884)version.py: new process should not create a window on Windows (#882, #886)setuptools_scm if the .git folder doesn't exist (#885)Documentation:
Nothing published for this version
Nothing published for this version
Parameterized methods that were deprecated since Param 1.7.0 have finally been removed. These are now mostly available on the .param namespace
20 years after its creation, Param has reached version 2.0! Can you guess when Param 3.0 will be released?
Param 2.0 is a major new release available for Python 3.8 and above, significantly streamlining, simplifying, and improving the Param API. Many long-supported but also long-obsolete functions, methods, and usages will now warn loudly so that you can make sure your code is only using the fully supported and safe current approaches. Because upgrading to Param 2 is likely to reveal compatibility issues with older codebases, new releases in the 1.x series are expected to continue for some time, focused on compatibility with the ecosystem rather than adding new features. Thus you can keep using Param 1.x with your older code, but Param 2 is the future!
We would like to thank @minimav for their first contribution, and @droumis, @Hoxbro, @jbednar, @maximlt, @philippjfr and @sdrobert for their contributions. We would also like to thank @ceball, who made the first plans for Param 2.0 quite a few years ago, and we are glad to be delivering on them at last!
B being a subclass of A, itself being a subclass of param.Parameterized. If A defines x = Number(1, bounds=(0, 10)) and B defines x = Number(2), B.param['x'].bounds is now going to be inherited from A and equal to (0, 10) as you would expect. Parameterized classes have always supported inheritance, but the previous mechanism was based on using None to indicate which values should be inherited, which was highly problematic because None was also a valid value for many slots. All Parameter slot signatures now default to the new Undefined sentinel, finally allowing None to be inherited where appropriate. (#605, #771, #791, #874)objects slot of a Selector was previously highly confusing, because it accepted either a dictionary or a list for initialization but then was accessible only as a list, making it difficult to watch or update the objects. There is now a ListProxy wrapper around Selector.objects (with forward and backward compatibility) to easily update objects and watch objects updates (#598, #825)p, just return p.param in a notebook cell to see a table of all the Parameters of the class/instance, their state, type, and range, plus the docstring on hover. It is likely we will improve the content and design of this repr based on feedback, so please let us know what you think! (#425, #781, #821, #831)allow_refs and nested_refs attributes, bringing an exceptionally useful feature that was available in Panel since version 1.2 to Param. Declaring a Parameter with allow_refs=True (False by default) allows setting this Parameter value with a reference to automatically mirror the value of the reference. Supported references include class/instance Parameter objects, functions/methods decorated with param.depends, reactive functions and expressions, asynchronous generators and custom objects transformed into a valid reference with a hook registered with param.parameterized.register_reference_transform. nested_refs indicate whether references should be resolved even when they are nested inside a container (#843, #845, #849, #865, #862, #876)rx reactive expressions: Param is widely used for building web apps in the HoloViz ecosystem, where packages have added various mechanisms for dynamic updates (e.g. pn.bind and pn.depends in Panel, and .interactive in hvPlot). These mechanisms were already built on Param and can be used far more widely than just in those packages, so that functionality has now been generalized, streamlined, and moved into Param. Nearly any Python expression can now be made reactive with param.rx(), at which point it will collect and be able to replay any operations (e.g. method calls) performed on them. This reactive programming approach lets you take just about any existing Python workflow and replace attributes with widgets or other reactive values, creating an app with fine-grained user control without having to design callbacks, event handlers, or any other complex logic! rx support is still experimental while we get feedback about the API, packaging, and documentation, but it's fully ready to try out and give us suggestions!
(#460, #842, #841, #844, #846, #847, #850, #851, #856, #860, #854, #859, #858, #873)Selector(objects=a_list)) will now be shallow-copied on instantiation, so that the container is no longer confusingly shared between the class and its subclasses and instances (#826)_param__private and _param__parameters (#766, #790).param.update as a context manager for applying temporary updates (#779)name Parameter has always had special behavior dating to its use in labeling objects in a GUI context, but this behavior is now able to be overriden at the class and instance level (#740)__signature__ support (#802)Array and DataFrame (#482)Integer now accepts numpy.integer values (#735)Range now does stricter validation of the slot values (#725, #824)Path now has check_exists attribute, leading it to raise an error if path is not found on parameter instantiation (#800)__all__ and move Parameter classes to parameters.py (#853)DateRange and Date (#733)self is present in the __init__ signature of a Parameterized class (#786)instantiate to True when constant is True (#776)Array: fix param.pprint (#795)Array: don't hard-code allow_None to True (#726)Boolean: validate the default type (#722)FileSelector: made more consistent with Selector by defaulting to the first globbed path (#801)FileSelector: ensure path separators are consistent on Windows (#805)Path: raise a ValueError if set to None while not allowed (#799)Selector: populate objects when check_on_set is False and default is not in objects (#794, #817)File/MultiFileSelector: updating path updates objects (#814)sphinx directly and refactor the API reference (#810)pydata-sphinx-theme (#752)hatch, pyproject.toml and pre-commit (#749, #772)asv (#788)Parameter classes should be updated to use Undefined as the formal default for any new slots, with the actual default defined on the new _slot_defaults dictionary. Otherwise, any new slot will fail to support inheritance, even if it was set to None, which would previously support inheritance.Parameterized methods that were deprecated since Param 1.7.0 have finally been removed. These are now mostly available on the .param namespace (#592)instance.param.watchers no longer returns the transient dict of watchers but instead returns the instance watchers, as the now deprecated instance._param_watchers (#797)Parameterized.pprint, Parameterized._pprint, Parameterized.script_repr, ParameterizedFunction.script_repr (#767)Time.next method needed only for Param 2, and moved Parameterized.state_pop and Parameterized.state_push to the .param namespace (#767)This section lists functionality that is expected to be removed sometime in the next couple of 2.x releases, so if you use Param 2, please take care of these warnings as soon as you encounter them, and certainly before you upgrade to the next release!
Param 2.0 adds a validation step of the default value of a Parameter after the inheritance mechanism has completed if its type has changed (e.g. x in class A is a Number and in class B(A) is an Integer) or one of its slot values has changed (#812, #820, #857). We have decided to only emit a warning when this validation fails to make your life easier when upgrading your code from Param 1 to 2, as the validation is performed on class creation which means that any validation error breaks importing your code. You should definitely take care of these warnings, they indicate a Parameter is in an invalid state!
We continue to clean up Param's API (#734, #751, #768, #797, #834, #838) but have decided to do it in a gentle way, emitting deprecation warnings for a period of time before proceeding with removals. You will find below the complete list of deprecation warnings added in Param 2.0.
default is deprecated:
String('prefix-test', '^prefix'): deprecated!String('prefix-test', regex='^prefix'): OKString(default='prefix-test', regex='^prefix'): OKSelector parameters that accept objects as first positional argument, and ClassSelector parameters that accept class_ as first positional argument, passing any argument by position is deprecated:
Selector([1, 2]): deprecated!Selector(objects=[1, 2]): OKClassSelector((str, int)): deprecated!ClassSelector(class_=(str, int)): OKdefault as first and only positional argument, but for now please use an explicit keyword so that your code will be compatible with all versions.List._class: use instead item_type.Number.set_hook: no replacementparam.__init__ module:
param.produce_value: no replacementparam.as_unicode: no replacementparam.is_ordered_dict: no replacementparam.is_ordered_dict: no replacementparam.hashable: no replacementparam.named_objs: no replacementparam.normalize_path: no replacementparam.abbreviate_paths: no replacementparam.parameterized module:
param.parameterized.all_equal: no replacementparam.parameterized.add_metaclass: no replacementparam.parameterized.batch_watch: use instead batch_call_watchersparam.parameterized.recursive_repr: no replacementparam.parameterized.overridable_property: no replacement.param namespace; many of these methods have been deprecated since version 1.12.0, however, this was just announced in the release notes and we realised many users missed them, sometimes even us included! They now all emit deprecation warnings when executed and are clearly marked as deprecated in the API reference:
.param.set_default: use instead for k,v in p.param.objects().items(): print(f"{p.__class__.name}.{k}={repr(v.default)}").param._add_parameter: use instead .param.add_parameter.param.params: use instead .param.values() or .param['param'].param.set_param: use instead .param.update.param.get_param_values: use instead .param.values().items() (or .param.values() for the common case of dict(....param.get_param_values())).param.params_depended_on: use instead .param.method_dependencies.param.defaults: use instead {k:v.default for k,v in p.param.objects().items()}.param.print_param_defaults: use instead for k,v in p.param.objects().items(): print(f"{p.__class__.name}.{k}={repr(v.default)}").param.print_param_values: use instead for k,v in p.param.objects().items(): print(f"{p.__class__.name}.{k}={repr(v.default)}").param.message: use instead .param.log(param.MESSAGE, ...).param.verbose: use instead .param.log(param.VERBOSE, ...).param.debug: use instead .param.log(param.DEBUG, ...)super().__init__(**params):
instance.param.objects(instance=True)instance.param.trigger("<param_name>")instance.param.watch(callback, "<param_name>")instance._param_watchers (getter and setter): use instead the property inst.param.watchersNothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Your coding agent can read these notes before it upgrades. Set up the MCP server →