Skip to content

Commit fe8f178

Browse files
authored
Add the metadata Parameter attribute (#1094)
1 parent 5309261 commit fe8f178

File tree

4 files changed

+209
-30
lines changed

4 files changed

+209
-30
lines changed

doc/user_guide/Parameters.ipynb

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
"- **precedence**: Optional numeric value controlling whether this parameter is visible in a listing and if so in what order.\n",
4141
"- **allow_refs**: Whether to allow the Parameter to accept references to other Parameters that will be dynamically resolved.\n",
4242
"- **nested_refs**: Whether references should be resolved even when they are nested inside a container.\n",
43+
"- **metadata**: Optional arbitrary mapping, to be used to store additional metadata than cannot be declared with the other attributes. Useful for third-party libraries to extend Param.\n",
4344
"\n",
4445
"Most of these settings (apart from **name**) are accepted as keyword arguments to the Parameter's constructor, with `default` mostly also accepted as the only positional argument:"
4546
]
@@ -929,6 +930,105 @@
929930
"Object().debug_id, SubObject().debug_id"
930931
]
931932
},
933+
{
934+
"cell_type": "code",
935+
"execution_count": null,
936+
"id": "b4a9751f-e307-4b9e-8c25-fc2059200152",
937+
"metadata": {},
938+
"outputs": [],
939+
"source": [
940+
"import param"
941+
]
942+
},
943+
{
944+
"cell_type": "markdown",
945+
"id": "32cc7b01-55a2-43dd-b886-acf0c30cb5ba",
946+
"metadata": {},
947+
"source": [
948+
"## Arbitrary Metadata\n",
949+
"\n",
950+
"Parameters may include arbitrary metadata as a mapping stored in the `metadata` attribute (default is `None`). This attribute is not used internally by Param, instead it is meant to enable rich functionality in third-party libraries, or to be leveraged in your own code base to extend Parameters with information that cannot be declared with the other attributes available. Note that a shallow copy of the mapping you'll pass will be made on class creation and on instance-level parameter creation. This behavior is not specific to the `metadata` attribute, it is how Param handles attributes with value that are mutable containers (lists, dicts, sets)."
951+
]
952+
},
953+
{
954+
"cell_type": "code",
955+
"execution_count": null,
956+
"id": "cf82e531-40f4-4960-9ba1-1df012711a93",
957+
"metadata": {},
958+
"outputs": [],
959+
"source": [
960+
"extra_info = {'library': {'config': True}}\n",
961+
"\n",
962+
"class P(param.Parameterized):\n",
963+
" s = param.String(metadata=extra_info)"
964+
]
965+
},
966+
{
967+
"cell_type": "code",
968+
"execution_count": null,
969+
"id": "c9f6182e-320d-4e54-b8aa-7596ccabdb29",
970+
"metadata": {},
971+
"outputs": [],
972+
"source": [
973+
"P.param['s'].metadata"
974+
]
975+
},
976+
{
977+
"cell_type": "code",
978+
"execution_count": null,
979+
"id": "9207c2f0-44de-4bed-8f80-753393fcf66f",
980+
"metadata": {},
981+
"outputs": [],
982+
"source": [
983+
"p = P()\n",
984+
"p.param.s.metadata"
985+
]
986+
},
987+
{
988+
"cell_type": "code",
989+
"execution_count": null,
990+
"id": "639dadc6-bf31-4eac-9327-8bcc12e0eb63",
991+
"metadata": {},
992+
"outputs": [],
993+
"source": [
994+
"P.param['s'].metadata is extra_info # shallow copy made on class creation"
995+
]
996+
},
997+
{
998+
"cell_type": "code",
999+
"execution_count": null,
1000+
"id": "d3cd5940-9b40-48a3-9fe1-4a14f2c6c803",
1001+
"metadata": {},
1002+
"outputs": [],
1003+
"source": [
1004+
"p.param['s'].metadata is P.param['s'].metadata # shallow copy made when the instance-level Parameter is created"
1005+
]
1006+
},
1007+
{
1008+
"cell_type": "markdown",
1009+
"id": "d0cfdb8c-29ac-4391-a0c8-353665e93e03",
1010+
"metadata": {},
1011+
"source": [
1012+
"To provide a more concrete example on how third-party libraries can benefit from the `metadata` attribute, we'll give an example with [Panel](https://panel.holoviz.org), a library to build web apps written in Python only. Panel already integrates with Param, and makes it easy to display a Parameterized instance as an app component, each Parameter type being automatically mapped to a widget type (e.g., a `Number` Parameter is displayed as a float slider). Customizing the automatically created widget requires additional work in Panel (e.g., using the `Widget.from_param(<parameter>)` API). To simplify this process, Panel could inspect the `metadata` attribute for custom widget configuration, and apply it on widget creation:"
1013+
]
1014+
},
1015+
{
1016+
"cell_type": "markdown",
1017+
"id": "4ee588b7-5715-4846-a079-3e5fe8e47cf5",
1018+
"metadata": {},
1019+
"source": [
1020+
"```python\n",
1021+
"import panel as pn\n",
1022+
"\n",
1023+
"pn.extension()\n",
1024+
"\n",
1025+
"class MyPanelView(param.Parameterized):\n",
1026+
" percentage = param.Number(default=0, bounds=(0, 100), metadata={'panel': {'width': 100}})\n",
1027+
"\n",
1028+
"pn.Param(MyPanelView())\n",
1029+
"```"
1030+
]
1031+
},
9321032
{
9331033
"cell_type": "markdown",
9341034
"id": "14a20588",

param/parameterized.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1317,7 +1317,8 @@ class Parameter(_ParameterBase):
13171317
__slots__ = ['name', 'default', 'default_factory', 'doc',
13181318
'precedence', 'instantiate', 'constant', 'readonly',
13191319
'pickle_default_value', 'allow_None', 'per_instance',
1320-
'watchers', 'owner', 'allow_refs', 'nested_refs', '_label']
1320+
'watchers', 'owner', 'allow_refs', 'nested_refs', '_label',
1321+
'metadata',]
13211322

13221323
# Note: When initially created, a Parameter does not know which
13231324
# Parameterized class owns it, nor does it know its names
@@ -1331,6 +1332,7 @@ class Parameter(_ParameterBase):
13311332
default=None, precedence=None, doc=None, _label=None, instantiate=False,
13321333
constant=False, readonly=False, pickle_default_value=True, allow_None=False,
13331334
per_instance=True, allow_refs=False, nested_refs=False, default_factory=None,
1335+
metadata=None,
13341336
)
13351337

13361338
# Parameters can be updated during Parameterized class creation when they
@@ -1339,15 +1341,15 @@ class Parameter(_ParameterBase):
13391341
# in this list do not have to trigger such re-validation.
13401342
_non_validated_slots = ['_label', 'doc', 'name', 'precedence',
13411343
'constant', 'pickle_default_value',
1342-
'watchers', 'owner']
1344+
'watchers', 'owner', 'metadata']
13431345

13441346
@typing.overload
13451347
def __init__(
13461348
self,
13471349
default=None, *,
13481350
doc=None, label=None, precedence=None, instantiate=False, constant=False,
13491351
readonly=False, pickle_default_value=True, allow_None=False, per_instance=True,
1350-
allow_refs=False, nested_refs=False, default_factory=None,
1352+
allow_refs=False, nested_refs=False, default_factory=None, metadata=None,
13511353
):
13521354
...
13531355

@@ -1367,6 +1369,7 @@ def __init__( # pylint: disable-msg=R0913
13671369
allow_refs=Undefined,
13681370
nested_refs=Undefined,
13691371
default_factory=Undefined,
1372+
metadata=Undefined,
13701373
):
13711374
"""
13721375
Initialize a new :class:`Parameter` object with the specified attributes.
@@ -1449,6 +1452,12 @@ def __init__( # pylint: disable-msg=R0913
14491452
If ``True`` and ``allow_refs=True``, inspects nested objects (e.g.,
14501453
dictionaries, lists, slices, tuples) for references and resolves
14511454
them automatically. Default is ``False``.
1455+
metadata : Mapping, optional
1456+
An arbitrary mapping, to be used to store additional metadata
1457+
than cannot be declared with the other attributes. Useful for
1458+
third-party libraries to extend Param. Default is ``None``.
1459+
1460+
.. versionadded:: 2.3.0
14521461
14531462
Examples
14541463
--------
@@ -1498,6 +1507,7 @@ def __init__( # pylint: disable-msg=R0913
14981507
)
14991508
self.pickle_default_value = pickle_default_value
15001509
self._set_allow_None(allow_None)
1510+
self.metadata = metadata
15011511
self.watchers = {}
15021512
self.per_instance = per_instance
15031513

@@ -1995,7 +2005,7 @@ def __init__(
19952005
default="", *, regex=None,
19962006
doc=None, label=None, precedence=None, instantiate=False, constant=False,
19972007
readonly=False, pickle_default_value=True, allow_None=False, per_instance=True,
1998-
allow_refs=False, nested_refs=False, default_factory=None
2008+
allow_refs=False, nested_refs=False, default_factory=None, metadata=None,
19992009
):
20002010
...
20012011

0 commit comments

Comments
 (0)