diff --git a/.buildinfo b/.buildinfo new file mode 100644 index 0000000..abe3e26 --- /dev/null +++ b/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: bdc0d196121379e3ffec847842ab0485 +tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/.doctrees/about.doctree b/.doctrees/about.doctree new file mode 100644 index 0000000..dbced42 Binary files /dev/null and b/.doctrees/about.doctree differ diff --git a/.doctrees/comparisons.doctree b/.doctrees/comparisons.doctree new file mode 100644 index 0000000..eca69ad Binary files /dev/null and b/.doctrees/comparisons.doctree differ diff --git a/.doctrees/developer_guide.doctree b/.doctrees/developer_guide.doctree new file mode 100644 index 0000000..ab347a4 Binary files /dev/null and b/.doctrees/developer_guide.doctree differ diff --git a/.doctrees/environment.pickle b/.doctrees/environment.pickle new file mode 100644 index 0000000..6109fc0 Binary files /dev/null and b/.doctrees/environment.pickle differ diff --git a/.doctrees/getting_started.doctree b/.doctrees/getting_started.doctree new file mode 100644 index 0000000..8485f5f Binary files /dev/null and b/.doctrees/getting_started.doctree differ diff --git a/.doctrees/index.doctree b/.doctrees/index.doctree new file mode 100644 index 0000000..1dbf7c6 Binary files /dev/null and b/.doctrees/index.doctree differ diff --git a/.doctrees/reference/index.doctree b/.doctrees/reference/index.doctree new file mode 100644 index 0000000..0d7792e Binary files /dev/null and b/.doctrees/reference/index.doctree differ diff --git a/.doctrees/reference/numbergen.doctree b/.doctrees/reference/numbergen.doctree new file mode 100644 index 0000000..188afd0 Binary files /dev/null and b/.doctrees/reference/numbergen.doctree differ diff --git a/.doctrees/reference/param/generated/param.Action.doctree b/.doctrees/reference/param/generated/param.Action.doctree new file mode 100644 index 0000000..7a97ad7 Binary files /dev/null and b/.doctrees/reference/param/generated/param.Action.doctree differ diff --git a/.doctrees/reference/param/generated/param.Array.doctree b/.doctrees/reference/param/generated/param.Array.doctree new file mode 100644 index 0000000..a5a2d98 Binary files /dev/null and b/.doctrees/reference/param/generated/param.Array.doctree differ diff --git a/.doctrees/reference/param/generated/param.Boolean.doctree b/.doctrees/reference/param/generated/param.Boolean.doctree new file mode 100644 index 0000000..9e1f367 Binary files /dev/null and b/.doctrees/reference/param/generated/param.Boolean.doctree differ diff --git a/.doctrees/reference/param/generated/param.Bytes.doctree b/.doctrees/reference/param/generated/param.Bytes.doctree new file mode 100644 index 0000000..306d73e Binary files /dev/null and b/.doctrees/reference/param/generated/param.Bytes.doctree differ diff --git a/.doctrees/reference/param/generated/param.CalendarDateRange.doctree b/.doctrees/reference/param/generated/param.CalendarDateRange.doctree new file mode 100644 index 0000000..8c06221 Binary files /dev/null and b/.doctrees/reference/param/generated/param.CalendarDateRange.doctree differ diff --git a/.doctrees/reference/param/generated/param.Callable.doctree b/.doctrees/reference/param/generated/param.Callable.doctree new file mode 100644 index 0000000..ee9a68d Binary files /dev/null and b/.doctrees/reference/param/generated/param.Callable.doctree differ diff --git a/.doctrees/reference/param/generated/param.ClassSelector.doctree b/.doctrees/reference/param/generated/param.ClassSelector.doctree new file mode 100644 index 0000000..60830b0 Binary files /dev/null and b/.doctrees/reference/param/generated/param.ClassSelector.doctree differ diff --git a/.doctrees/reference/param/generated/param.Color.doctree b/.doctrees/reference/param/generated/param.Color.doctree new file mode 100644 index 0000000..c805ede Binary files /dev/null and b/.doctrees/reference/param/generated/param.Color.doctree differ diff --git a/.doctrees/reference/param/generated/param.Composite.doctree b/.doctrees/reference/param/generated/param.Composite.doctree new file mode 100644 index 0000000..b480d35 Binary files /dev/null and b/.doctrees/reference/param/generated/param.Composite.doctree differ diff --git a/.doctrees/reference/param/generated/param.DataFrame.doctree b/.doctrees/reference/param/generated/param.DataFrame.doctree new file mode 100644 index 0000000..1a09640 Binary files /dev/null and b/.doctrees/reference/param/generated/param.DataFrame.doctree differ diff --git a/.doctrees/reference/param/generated/param.DateRange.doctree b/.doctrees/reference/param/generated/param.DateRange.doctree new file mode 100644 index 0000000..8989659 Binary files /dev/null and b/.doctrees/reference/param/generated/param.DateRange.doctree differ diff --git a/.doctrees/reference/param/generated/param.Dict.doctree b/.doctrees/reference/param/generated/param.Dict.doctree new file mode 100644 index 0000000..3676d35 Binary files /dev/null and b/.doctrees/reference/param/generated/param.Dict.doctree differ diff --git a/.doctrees/reference/param/generated/param.Dynamic.doctree b/.doctrees/reference/param/generated/param.Dynamic.doctree new file mode 100644 index 0000000..323504d Binary files /dev/null and b/.doctrees/reference/param/generated/param.Dynamic.doctree differ diff --git a/.doctrees/reference/param/generated/param.Event.doctree b/.doctrees/reference/param/generated/param.Event.doctree new file mode 100644 index 0000000..95eb917 Binary files /dev/null and b/.doctrees/reference/param/generated/param.Event.doctree differ diff --git a/.doctrees/reference/param/generated/param.FileSelector.doctree b/.doctrees/reference/param/generated/param.FileSelector.doctree new file mode 100644 index 0000000..deed58e Binary files /dev/null and b/.doctrees/reference/param/generated/param.FileSelector.doctree differ diff --git a/.doctrees/reference/param/generated/param.Filename.doctree b/.doctrees/reference/param/generated/param.Filename.doctree new file mode 100644 index 0000000..32e8260 Binary files /dev/null and b/.doctrees/reference/param/generated/param.Filename.doctree differ diff --git a/.doctrees/reference/param/generated/param.Foldername.doctree b/.doctrees/reference/param/generated/param.Foldername.doctree new file mode 100644 index 0000000..f17099f Binary files /dev/null and b/.doctrees/reference/param/generated/param.Foldername.doctree differ diff --git a/.doctrees/reference/param/generated/param.HookList.doctree b/.doctrees/reference/param/generated/param.HookList.doctree new file mode 100644 index 0000000..7c6a948 Binary files /dev/null and b/.doctrees/reference/param/generated/param.HookList.doctree differ diff --git a/.doctrees/reference/param/generated/param.Integer.doctree b/.doctrees/reference/param/generated/param.Integer.doctree new file mode 100644 index 0000000..db5b0fc Binary files /dev/null and b/.doctrees/reference/param/generated/param.Integer.doctree differ diff --git a/.doctrees/reference/param/generated/param.List.doctree b/.doctrees/reference/param/generated/param.List.doctree new file mode 100644 index 0000000..be197d2 Binary files /dev/null and b/.doctrees/reference/param/generated/param.List.doctree differ diff --git a/.doctrees/reference/param/generated/param.ListSelector.doctree b/.doctrees/reference/param/generated/param.ListSelector.doctree new file mode 100644 index 0000000..6fc934b Binary files /dev/null and b/.doctrees/reference/param/generated/param.ListSelector.doctree differ diff --git a/.doctrees/reference/param/generated/param.Magnitude.doctree b/.doctrees/reference/param/generated/param.Magnitude.doctree new file mode 100644 index 0000000..2069efe Binary files /dev/null and b/.doctrees/reference/param/generated/param.Magnitude.doctree differ diff --git a/.doctrees/reference/param/generated/param.MultiFileSelector.doctree b/.doctrees/reference/param/generated/param.MultiFileSelector.doctree new file mode 100644 index 0000000..61c39b1 Binary files /dev/null and b/.doctrees/reference/param/generated/param.MultiFileSelector.doctree differ diff --git a/.doctrees/reference/param/generated/param.Number.doctree b/.doctrees/reference/param/generated/param.Number.doctree new file mode 100644 index 0000000..acec152 Binary files /dev/null and b/.doctrees/reference/param/generated/param.Number.doctree differ diff --git a/.doctrees/reference/param/generated/param.NumericTuple.doctree b/.doctrees/reference/param/generated/param.NumericTuple.doctree new file mode 100644 index 0000000..857767a Binary files /dev/null and b/.doctrees/reference/param/generated/param.NumericTuple.doctree differ diff --git a/.doctrees/reference/param/generated/param.ParamOverrides.doctree b/.doctrees/reference/param/generated/param.ParamOverrides.doctree new file mode 100644 index 0000000..9d3eae2 Binary files /dev/null and b/.doctrees/reference/param/generated/param.ParamOverrides.doctree differ diff --git a/.doctrees/reference/param/generated/param.Parameter.doctree b/.doctrees/reference/param/generated/param.Parameter.doctree new file mode 100644 index 0000000..c211dbb Binary files /dev/null and b/.doctrees/reference/param/generated/param.Parameter.doctree differ diff --git a/.doctrees/reference/param/generated/param.Parameterized.doctree b/.doctrees/reference/param/generated/param.Parameterized.doctree new file mode 100644 index 0000000..d8b52d5 Binary files /dev/null and b/.doctrees/reference/param/generated/param.Parameterized.doctree differ diff --git a/.doctrees/reference/param/generated/param.ParameterizedFunction.doctree b/.doctrees/reference/param/generated/param.ParameterizedFunction.doctree new file mode 100644 index 0000000..e829cca Binary files /dev/null and b/.doctrees/reference/param/generated/param.ParameterizedFunction.doctree differ diff --git a/.doctrees/reference/param/generated/param.Path.doctree b/.doctrees/reference/param/generated/param.Path.doctree new file mode 100644 index 0000000..e93314d Binary files /dev/null and b/.doctrees/reference/param/generated/param.Path.doctree differ diff --git a/.doctrees/reference/param/generated/param.Range.doctree b/.doctrees/reference/param/generated/param.Range.doctree new file mode 100644 index 0000000..0e97200 Binary files /dev/null and b/.doctrees/reference/param/generated/param.Range.doctree differ diff --git a/.doctrees/reference/param/generated/param.Selector.doctree b/.doctrees/reference/param/generated/param.Selector.doctree new file mode 100644 index 0000000..5755b7c Binary files /dev/null and b/.doctrees/reference/param/generated/param.Selector.doctree differ diff --git a/.doctrees/reference/param/generated/param.Series.doctree b/.doctrees/reference/param/generated/param.Series.doctree new file mode 100644 index 0000000..7fc5bd1 Binary files /dev/null and b/.doctrees/reference/param/generated/param.Series.doctree differ diff --git a/.doctrees/reference/param/generated/param.String.doctree b/.doctrees/reference/param/generated/param.String.doctree new file mode 100644 index 0000000..3e544d9 Binary files /dev/null and b/.doctrees/reference/param/generated/param.String.doctree differ diff --git a/.doctrees/reference/param/generated/param.Tuple.doctree b/.doctrees/reference/param/generated/param.Tuple.doctree new file mode 100644 index 0000000..9c655b5 Binary files /dev/null and b/.doctrees/reference/param/generated/param.Tuple.doctree differ diff --git a/.doctrees/reference/param/generated/param.XYCoordinates.doctree b/.doctrees/reference/param/generated/param.XYCoordinates.doctree new file mode 100644 index 0000000..1b8ff65 Binary files /dev/null and b/.doctrees/reference/param/generated/param.XYCoordinates.doctree differ diff --git a/.doctrees/reference/param/generated/param.batch_watch.doctree b/.doctrees/reference/param/generated/param.batch_watch.doctree new file mode 100644 index 0000000..f95cd9a Binary files /dev/null and b/.doctrees/reference/param/generated/param.batch_watch.doctree differ diff --git a/.doctrees/reference/param/generated/param.concrete_descendents.doctree b/.doctrees/reference/param/generated/param.concrete_descendents.doctree new file mode 100644 index 0000000..7dac581 Binary files /dev/null and b/.doctrees/reference/param/generated/param.concrete_descendents.doctree differ diff --git a/.doctrees/reference/param/generated/param.depends.doctree b/.doctrees/reference/param/generated/param.depends.doctree new file mode 100644 index 0000000..270f9c4 Binary files /dev/null and b/.doctrees/reference/param/generated/param.depends.doctree differ diff --git a/.doctrees/reference/param/generated/param.discard_events.doctree b/.doctrees/reference/param/generated/param.discard_events.doctree new file mode 100644 index 0000000..3c5e39a Binary files /dev/null and b/.doctrees/reference/param/generated/param.discard_events.doctree differ diff --git a/.doctrees/reference/param/generated/param.edit_constant.doctree b/.doctrees/reference/param/generated/param.edit_constant.doctree new file mode 100644 index 0000000..5433bb2 Binary files /dev/null and b/.doctrees/reference/param/generated/param.edit_constant.doctree differ diff --git a/.doctrees/reference/param/generated/param.get_soft_bounds.doctree b/.doctrees/reference/param/generated/param.get_soft_bounds.doctree new file mode 100644 index 0000000..742fb44 Binary files /dev/null and b/.doctrees/reference/param/generated/param.get_soft_bounds.doctree differ diff --git a/.doctrees/reference/param/generated/param.guess_bounds.doctree b/.doctrees/reference/param/generated/param.guess_bounds.doctree new file mode 100644 index 0000000..0f11d03 Binary files /dev/null and b/.doctrees/reference/param/generated/param.guess_bounds.doctree differ diff --git a/.doctrees/reference/param/generated/param.guess_param_types.doctree b/.doctrees/reference/param/generated/param.guess_param_types.doctree new file mode 100644 index 0000000..e189f52 Binary files /dev/null and b/.doctrees/reference/param/generated/param.guess_param_types.doctree differ diff --git a/.doctrees/reference/param/generated/param.output.doctree b/.doctrees/reference/param/generated/param.output.doctree new file mode 100644 index 0000000..36e3ae7 Binary files /dev/null and b/.doctrees/reference/param/generated/param.output.doctree differ diff --git a/.doctrees/reference/param/generated/param.param_union.doctree b/.doctrees/reference/param/generated/param.param_union.doctree new file mode 100644 index 0000000..e40897c Binary files /dev/null and b/.doctrees/reference/param/generated/param.param_union.doctree differ diff --git a/.doctrees/reference/param/generated/param.parameterized.Event.doctree b/.doctrees/reference/param/generated/param.parameterized.Event.doctree new file mode 100644 index 0000000..024cdf8 Binary files /dev/null and b/.doctrees/reference/param/generated/param.parameterized.Event.doctree differ diff --git a/.doctrees/reference/param/generated/param.parameterized.Parameters.add_parameter.doctree b/.doctrees/reference/param/generated/param.parameterized.Parameters.add_parameter.doctree new file mode 100644 index 0000000..8e06553 Binary files /dev/null and b/.doctrees/reference/param/generated/param.parameterized.Parameters.add_parameter.doctree differ diff --git a/.doctrees/reference/param/generated/param.parameterized.Parameters.debug.doctree b/.doctrees/reference/param/generated/param.parameterized.Parameters.debug.doctree new file mode 100644 index 0000000..d1301ca Binary files /dev/null and b/.doctrees/reference/param/generated/param.parameterized.Parameters.debug.doctree differ diff --git a/.doctrees/reference/param/generated/param.parameterized.Parameters.defaults.doctree b/.doctrees/reference/param/generated/param.parameterized.Parameters.defaults.doctree new file mode 100644 index 0000000..2d04120 Binary files /dev/null and b/.doctrees/reference/param/generated/param.parameterized.Parameters.defaults.doctree differ diff --git a/.doctrees/reference/param/generated/param.parameterized.Parameters.deserialize_parameters.doctree b/.doctrees/reference/param/generated/param.parameterized.Parameters.deserialize_parameters.doctree new file mode 100644 index 0000000..d2be77f Binary files /dev/null and b/.doctrees/reference/param/generated/param.parameterized.Parameters.deserialize_parameters.doctree differ diff --git a/.doctrees/reference/param/generated/param.parameterized.Parameters.deserialize_value.doctree b/.doctrees/reference/param/generated/param.parameterized.Parameters.deserialize_value.doctree new file mode 100644 index 0000000..c435d83 Binary files /dev/null and b/.doctrees/reference/param/generated/param.parameterized.Parameters.deserialize_value.doctree differ diff --git a/.doctrees/reference/param/generated/param.parameterized.Parameters.force_new_dynamic_value.doctree b/.doctrees/reference/param/generated/param.parameterized.Parameters.force_new_dynamic_value.doctree new file mode 100644 index 0000000..aec6b75 Binary files /dev/null and b/.doctrees/reference/param/generated/param.parameterized.Parameters.force_new_dynamic_value.doctree differ diff --git a/.doctrees/reference/param/generated/param.parameterized.Parameters.get_param_values.doctree b/.doctrees/reference/param/generated/param.parameterized.Parameters.get_param_values.doctree new file mode 100644 index 0000000..c9b34b8 Binary files /dev/null and b/.doctrees/reference/param/generated/param.parameterized.Parameters.get_param_values.doctree differ diff --git a/.doctrees/reference/param/generated/param.parameterized.Parameters.get_value_generator.doctree b/.doctrees/reference/param/generated/param.parameterized.Parameters.get_value_generator.doctree new file mode 100644 index 0000000..5d1d421 Binary files /dev/null and b/.doctrees/reference/param/generated/param.parameterized.Parameters.get_value_generator.doctree differ diff --git a/.doctrees/reference/param/generated/param.parameterized.Parameters.inspect_value.doctree b/.doctrees/reference/param/generated/param.parameterized.Parameters.inspect_value.doctree new file mode 100644 index 0000000..7f2618d Binary files /dev/null and b/.doctrees/reference/param/generated/param.parameterized.Parameters.inspect_value.doctree differ diff --git a/.doctrees/reference/param/generated/param.parameterized.Parameters.log.doctree b/.doctrees/reference/param/generated/param.parameterized.Parameters.log.doctree new file mode 100644 index 0000000..240b8bf Binary files /dev/null and b/.doctrees/reference/param/generated/param.parameterized.Parameters.log.doctree differ diff --git a/.doctrees/reference/param/generated/param.parameterized.Parameters.message.doctree b/.doctrees/reference/param/generated/param.parameterized.Parameters.message.doctree new file mode 100644 index 0000000..7527596 Binary files /dev/null and b/.doctrees/reference/param/generated/param.parameterized.Parameters.message.doctree differ diff --git a/.doctrees/reference/param/generated/param.parameterized.Parameters.method_dependencies.doctree b/.doctrees/reference/param/generated/param.parameterized.Parameters.method_dependencies.doctree new file mode 100644 index 0000000..8fee2f9 Binary files /dev/null and b/.doctrees/reference/param/generated/param.parameterized.Parameters.method_dependencies.doctree differ diff --git a/.doctrees/reference/param/generated/param.parameterized.Parameters.objects.doctree b/.doctrees/reference/param/generated/param.parameterized.Parameters.objects.doctree new file mode 100644 index 0000000..440d7a3 Binary files /dev/null and b/.doctrees/reference/param/generated/param.parameterized.Parameters.objects.doctree differ diff --git a/.doctrees/reference/param/generated/param.parameterized.Parameters.outputs.doctree b/.doctrees/reference/param/generated/param.parameterized.Parameters.outputs.doctree new file mode 100644 index 0000000..8802c2c Binary files /dev/null and b/.doctrees/reference/param/generated/param.parameterized.Parameters.outputs.doctree differ diff --git a/.doctrees/reference/param/generated/param.parameterized.Parameters.params.doctree b/.doctrees/reference/param/generated/param.parameterized.Parameters.params.doctree new file mode 100644 index 0000000..c58e189 Binary files /dev/null and b/.doctrees/reference/param/generated/param.parameterized.Parameters.params.doctree differ diff --git a/.doctrees/reference/param/generated/param.parameterized.Parameters.params_depended_on.doctree b/.doctrees/reference/param/generated/param.parameterized.Parameters.params_depended_on.doctree new file mode 100644 index 0000000..048bede Binary files /dev/null and b/.doctrees/reference/param/generated/param.parameterized.Parameters.params_depended_on.doctree differ diff --git a/.doctrees/reference/param/generated/param.parameterized.Parameters.pprint.doctree b/.doctrees/reference/param/generated/param.parameterized.Parameters.pprint.doctree new file mode 100644 index 0000000..1627eda Binary files /dev/null and b/.doctrees/reference/param/generated/param.parameterized.Parameters.pprint.doctree differ diff --git a/.doctrees/reference/param/generated/param.parameterized.Parameters.print_param_defaults.doctree b/.doctrees/reference/param/generated/param.parameterized.Parameters.print_param_defaults.doctree new file mode 100644 index 0000000..5e4f017 Binary files /dev/null and b/.doctrees/reference/param/generated/param.parameterized.Parameters.print_param_defaults.doctree differ diff --git a/.doctrees/reference/param/generated/param.parameterized.Parameters.print_param_values.doctree b/.doctrees/reference/param/generated/param.parameterized.Parameters.print_param_values.doctree new file mode 100644 index 0000000..207a11e Binary files /dev/null and b/.doctrees/reference/param/generated/param.parameterized.Parameters.print_param_values.doctree differ diff --git a/.doctrees/reference/param/generated/param.parameterized.Parameters.schema.doctree b/.doctrees/reference/param/generated/param.parameterized.Parameters.schema.doctree new file mode 100644 index 0000000..1723669 Binary files /dev/null and b/.doctrees/reference/param/generated/param.parameterized.Parameters.schema.doctree differ diff --git a/.doctrees/reference/param/generated/param.parameterized.Parameters.serialize_parameters.doctree b/.doctrees/reference/param/generated/param.parameterized.Parameters.serialize_parameters.doctree new file mode 100644 index 0000000..e970265 Binary files /dev/null and b/.doctrees/reference/param/generated/param.parameterized.Parameters.serialize_parameters.doctree differ diff --git a/.doctrees/reference/param/generated/param.parameterized.Parameters.serialize_value.doctree b/.doctrees/reference/param/generated/param.parameterized.Parameters.serialize_value.doctree new file mode 100644 index 0000000..52803fd Binary files /dev/null and b/.doctrees/reference/param/generated/param.parameterized.Parameters.serialize_value.doctree differ diff --git a/.doctrees/reference/param/generated/param.parameterized.Parameters.set_default.doctree b/.doctrees/reference/param/generated/param.parameterized.Parameters.set_default.doctree new file mode 100644 index 0000000..58d9172 Binary files /dev/null and b/.doctrees/reference/param/generated/param.parameterized.Parameters.set_default.doctree differ diff --git a/.doctrees/reference/param/generated/param.parameterized.Parameters.set_dynamic_time_fn.doctree b/.doctrees/reference/param/generated/param.parameterized.Parameters.set_dynamic_time_fn.doctree new file mode 100644 index 0000000..df5ab64 Binary files /dev/null and b/.doctrees/reference/param/generated/param.parameterized.Parameters.set_dynamic_time_fn.doctree differ diff --git a/.doctrees/reference/param/generated/param.parameterized.Parameters.set_param.doctree b/.doctrees/reference/param/generated/param.parameterized.Parameters.set_param.doctree new file mode 100644 index 0000000..edcbb51 Binary files /dev/null and b/.doctrees/reference/param/generated/param.parameterized.Parameters.set_param.doctree differ diff --git a/.doctrees/reference/param/generated/param.parameterized.Parameters.trigger.doctree b/.doctrees/reference/param/generated/param.parameterized.Parameters.trigger.doctree new file mode 100644 index 0000000..e3d070f Binary files /dev/null and b/.doctrees/reference/param/generated/param.parameterized.Parameters.trigger.doctree differ diff --git a/.doctrees/reference/param/generated/param.parameterized.Parameters.unwatch.doctree b/.doctrees/reference/param/generated/param.parameterized.Parameters.unwatch.doctree new file mode 100644 index 0000000..6b61283 Binary files /dev/null and b/.doctrees/reference/param/generated/param.parameterized.Parameters.unwatch.doctree differ diff --git a/.doctrees/reference/param/generated/param.parameterized.Parameters.update.doctree b/.doctrees/reference/param/generated/param.parameterized.Parameters.update.doctree new file mode 100644 index 0000000..cabcef4 Binary files /dev/null and b/.doctrees/reference/param/generated/param.parameterized.Parameters.update.doctree differ diff --git a/.doctrees/reference/param/generated/param.parameterized.Parameters.values.doctree b/.doctrees/reference/param/generated/param.parameterized.Parameters.values.doctree new file mode 100644 index 0000000..67abb0a Binary files /dev/null and b/.doctrees/reference/param/generated/param.parameterized.Parameters.values.doctree differ diff --git a/.doctrees/reference/param/generated/param.parameterized.Parameters.verbose.doctree b/.doctrees/reference/param/generated/param.parameterized.Parameters.verbose.doctree new file mode 100644 index 0000000..e8ece93 Binary files /dev/null and b/.doctrees/reference/param/generated/param.parameterized.Parameters.verbose.doctree differ diff --git a/.doctrees/reference/param/generated/param.parameterized.Parameters.warning.doctree b/.doctrees/reference/param/generated/param.parameterized.Parameters.warning.doctree new file mode 100644 index 0000000..7e706bd Binary files /dev/null and b/.doctrees/reference/param/generated/param.parameterized.Parameters.warning.doctree differ diff --git a/.doctrees/reference/param/generated/param.parameterized.Parameters.watch.doctree b/.doctrees/reference/param/generated/param.parameterized.Parameters.watch.doctree new file mode 100644 index 0000000..a48f7af Binary files /dev/null and b/.doctrees/reference/param/generated/param.parameterized.Parameters.watch.doctree differ diff --git a/.doctrees/reference/param/generated/param.parameterized.Parameters.watch_values.doctree b/.doctrees/reference/param/generated/param.parameterized.Parameters.watch_values.doctree new file mode 100644 index 0000000..28121b9 Binary files /dev/null and b/.doctrees/reference/param/generated/param.parameterized.Parameters.watch_values.doctree differ diff --git a/.doctrees/reference/param/generated/param.parameterized.Parameters.watchers.doctree b/.doctrees/reference/param/generated/param.parameterized.Parameters.watchers.doctree new file mode 100644 index 0000000..e70450c Binary files /dev/null and b/.doctrees/reference/param/generated/param.parameterized.Parameters.watchers.doctree differ diff --git a/.doctrees/reference/param/generated/param.parameterized.Watcher.doctree b/.doctrees/reference/param/generated/param.parameterized.Watcher.doctree new file mode 100644 index 0000000..d75fc2b Binary files /dev/null and b/.doctrees/reference/param/generated/param.parameterized.Watcher.doctree differ diff --git a/.doctrees/reference/param/generated/param.parameterized.batch_call_watchers.doctree b/.doctrees/reference/param/generated/param.parameterized.batch_call_watchers.doctree new file mode 100644 index 0000000..9ecfe5e Binary files /dev/null and b/.doctrees/reference/param/generated/param.parameterized.batch_call_watchers.doctree differ diff --git a/.doctrees/reference/param/generated/param.parameterized.get_logger.doctree b/.doctrees/reference/param/generated/param.parameterized.get_logger.doctree new file mode 100644 index 0000000..0a3b9d1 Binary files /dev/null and b/.doctrees/reference/param/generated/param.parameterized.get_logger.doctree differ diff --git a/.doctrees/reference/param/generated/param.parameterized.logging_level.doctree b/.doctrees/reference/param/generated/param.parameterized.logging_level.doctree new file mode 100644 index 0000000..0e291cd Binary files /dev/null and b/.doctrees/reference/param/generated/param.parameterized.logging_level.doctree differ diff --git a/.doctrees/reference/param/generated/param.script_repr.doctree b/.doctrees/reference/param/generated/param.script_repr.doctree new file mode 100644 index 0000000..ace709b Binary files /dev/null and b/.doctrees/reference/param/generated/param.script_repr.doctree differ diff --git a/.doctrees/reference/param/index.doctree b/.doctrees/reference/param/index.doctree new file mode 100644 index 0000000..3f09871 Binary files /dev/null and b/.doctrees/reference/param/index.doctree differ diff --git a/.doctrees/reference/param/logging.doctree b/.doctrees/reference/param/logging.doctree new file mode 100644 index 0000000..f230466 Binary files /dev/null and b/.doctrees/reference/param/logging.doctree differ diff --git a/.doctrees/reference/param/param_namespace.doctree b/.doctrees/reference/param/param_namespace.doctree new file mode 100644 index 0000000..13f96d8 Binary files /dev/null and b/.doctrees/reference/param/param_namespace.doctree differ diff --git a/.doctrees/reference/param/parameter_helpers.doctree b/.doctrees/reference/param/parameter_helpers.doctree new file mode 100644 index 0000000..c655f9c Binary files /dev/null and b/.doctrees/reference/param/parameter_helpers.doctree differ diff --git a/.doctrees/reference/param/parameterized_helpers.doctree b/.doctrees/reference/param/parameterized_helpers.doctree new file mode 100644 index 0000000..64d92c4 Binary files /dev/null and b/.doctrees/reference/param/parameterized_helpers.doctree differ diff --git a/.doctrees/reference/param/parameterized_objects.doctree b/.doctrees/reference/param/parameterized_objects.doctree new file mode 100644 index 0000000..83ef7b4 Binary files /dev/null and b/.doctrees/reference/param/parameterized_objects.doctree differ diff --git a/.doctrees/reference/param/parameters.doctree b/.doctrees/reference/param/parameters.doctree new file mode 100644 index 0000000..28444f0 Binary files /dev/null and b/.doctrees/reference/param/parameters.doctree differ diff --git a/.doctrees/reference/param/serialization.doctree b/.doctrees/reference/param/serialization.doctree new file mode 100644 index 0000000..b58776d Binary files /dev/null and b/.doctrees/reference/param/serialization.doctree differ diff --git a/.doctrees/releases.doctree b/.doctrees/releases.doctree new file mode 100644 index 0000000..cf3484a Binary files /dev/null and b/.doctrees/releases.doctree differ diff --git a/.doctrees/roadmap.doctree b/.doctrees/roadmap.doctree new file mode 100644 index 0000000..6523bb4 Binary files /dev/null and b/.doctrees/roadmap.doctree differ diff --git a/.doctrees/user_guide/Dependencies_and_Watchers.doctree b/.doctrees/user_guide/Dependencies_and_Watchers.doctree new file mode 100644 index 0000000..a8cabf8 Binary files /dev/null and b/.doctrees/user_guide/Dependencies_and_Watchers.doctree differ diff --git a/.doctrees/user_guide/Dynamic_Parameters.doctree b/.doctrees/user_guide/Dynamic_Parameters.doctree new file mode 100644 index 0000000..239a0c5 Binary files /dev/null and b/.doctrees/user_guide/Dynamic_Parameters.doctree differ diff --git a/.doctrees/user_guide/How_Param_Works.doctree b/.doctrees/user_guide/How_Param_Works.doctree new file mode 100644 index 0000000..2f1ebbe Binary files /dev/null and b/.doctrees/user_guide/How_Param_Works.doctree differ diff --git a/.doctrees/user_guide/Logging_and_Warnings.doctree b/.doctrees/user_guide/Logging_and_Warnings.doctree new file mode 100644 index 0000000..8ae3c96 Binary files /dev/null and b/.doctrees/user_guide/Logging_and_Warnings.doctree differ diff --git a/.doctrees/user_guide/Outputs.doctree b/.doctrees/user_guide/Outputs.doctree new file mode 100644 index 0000000..837d49a Binary files /dev/null and b/.doctrees/user_guide/Outputs.doctree differ diff --git a/.doctrees/user_guide/Parameter_Types.doctree b/.doctrees/user_guide/Parameter_Types.doctree new file mode 100644 index 0000000..40f98e2 Binary files /dev/null and b/.doctrees/user_guide/Parameter_Types.doctree differ diff --git a/.doctrees/user_guide/ParameterizedFunctions.doctree b/.doctrees/user_guide/ParameterizedFunctions.doctree new file mode 100644 index 0000000..ba463ec Binary files /dev/null and b/.doctrees/user_guide/ParameterizedFunctions.doctree differ diff --git a/.doctrees/user_guide/Parameters.doctree b/.doctrees/user_guide/Parameters.doctree new file mode 100644 index 0000000..f7a5513 Binary files /dev/null and b/.doctrees/user_guide/Parameters.doctree differ diff --git a/.doctrees/user_guide/Reactive_Expressions.doctree b/.doctrees/user_guide/Reactive_Expressions.doctree new file mode 100644 index 0000000..78f3bc5 Binary files /dev/null and b/.doctrees/user_guide/Reactive_Expressions.doctree differ diff --git a/.doctrees/user_guide/Serialization_and_Persistence.doctree b/.doctrees/user_guide/Serialization_and_Persistence.doctree new file mode 100644 index 0000000..a6d8eeb Binary files /dev/null and b/.doctrees/user_guide/Serialization_and_Persistence.doctree differ diff --git a/.doctrees/user_guide/Simplifying_Codebases.doctree b/.doctrees/user_guide/Simplifying_Codebases.doctree new file mode 100644 index 0000000..ccff1ef Binary files /dev/null and b/.doctrees/user_guide/Simplifying_Codebases.doctree differ diff --git a/.doctrees/user_guide/index.doctree b/.doctrees/user_guide/index.doctree new file mode 100644 index 0000000..1e37840 Binary files /dev/null and b/.doctrees/user_guide/index.doctree differ diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/_modules/index.html b/_modules/index.html new file mode 100644 index 0000000..a139a9a --- /dev/null +++ b/_modules/index.html @@ -0,0 +1,656 @@ + + + + + + + + + + + Overview: module code — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + + + + + +
+ +
+ +
+
+
+ +
+ +
+ +
+ + + + +
+ + +
+
+
+ + + + + + + + \ No newline at end of file diff --git a/_modules/numbergen.html b/_modules/numbergen.html new file mode 100644 index 0000000..ad755a9 --- /dev/null +++ b/_modules/numbergen.html @@ -0,0 +1,1421 @@ + + + + + + + + + + + numbergen — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +

Source code for numbergen

+"""
+Callable objects that generate numbers according to different distributions.
+"""
+
+import random
+import operator
+import hashlib
+import struct
+import fractions
+
+from ctypes import c_size_t
+from math import e,pi
+
+import param
+
+
+from param import __version__  # noqa: API import
+
+class TimeAware(param.Parameterized):
+    """
+    Class of objects that have access to a global time function
+    and have the option of using it to generate time-dependent values
+    as necessary.
+
+    In the simplest case, an object could act as a strict function of
+    time, returning the current time transformed according to a fixed
+    equation.  Other objects may support locking their results to a
+    timebase, but also work without time.  For instance, objects with
+    random state could return a new random value for every call, with
+    no notion of time, or could always return the same value until the
+    global time changes.  Subclasses should thus provide an ability to
+    return a time-dependent value, but may not always do so.
+    """
+
+    time_dependent = param.Boolean(default=False,  doc="""
+       Whether the given time_fn should be used to constrain the
+       results generated.""")
+
+    time_fn = param.Callable(default=param.Dynamic.time_fn, doc="""
+        Callable used to specify the time that determines the state
+        and return value of the object, if time_dependent=True.""")
+
+
+    def __init__(self, **params):
+        super().__init__(**params)
+        self._check_time_fn()
+
+
+    def _check_time_fn(self, time_instance=False):
+        """
+        If time_fn is the global time function supplied by
+        param.Dynamic.time_fn, make sure Dynamic parameters are using
+        this time function to control their behaviour.
+
+        If time_instance is True, time_fn must be a param.Time instance.
+        """
+        if time_instance and not isinstance(self.time_fn, param.Time):
+            raise AssertionError("%s requires a Time object"
+                                 % self.__class__.__name__)
+
+        if self.time_dependent:
+            global_timefn = self.time_fn is param.Dynamic.time_fn
+            if global_timefn and not param.Dynamic.time_dependent:
+                raise AssertionError("Cannot use Dynamic.time_fn as"
+                                     " parameters are ignoring time.")
+
+
+class TimeDependent(TimeAware):
+    """
+    Objects that have access to a time function that determines the
+    output value. As a function of time, this type of object should
+    allow time values to be randomly jumped forwards or backwards,
+    but for a given time point, the results should remain constant.
+
+    The time_fn must be an instance of param.Time, to ensure all the
+    facilities necessary for safely navigating the timeline are
+    available.
+    """
+
+    time_dependent = param.Boolean(default=True, readonly=True, doc="""
+       Read-only parameter that is always True.""")
+
+    def _check_time_fn(self):
+        super()._check_time_fn(time_instance=True)
+
+
+
+
[docs]class NumberGenerator(param.Parameterized): + """ + Abstract base class for any object that when called produces a number. + + Primarily provides support for using NumberGenerators in simple + arithmetic expressions, such as abs((x+y)/z), where x,y,z are + NumberGenerators or numbers. + """ + + def __call__(self): + raise NotImplementedError + + # Could define any of Python's operators here, esp. if they have operator or ufunc equivalents + def __add__ (self,operand): return BinaryOperator(self,operand,operator.add) + def __sub__ (self,operand): return BinaryOperator(self,operand,operator.sub) + def __mul__ (self,operand): return BinaryOperator(self,operand,operator.mul) + def __mod__ (self,operand): return BinaryOperator(self,operand,operator.mod) + def __pow__ (self,operand): return BinaryOperator(self,operand,operator.pow) + def __div__ (self,operand): return BinaryOperator(self,operand,operator.div) + def __truediv__ (self,operand): return BinaryOperator(self,operand,operator.truediv) + def __floordiv__ (self,operand): return BinaryOperator(self,operand,operator.floordiv) + + def __radd__ (self,operand): return BinaryOperator(self,operand,operator.add,True) + def __rsub__ (self,operand): return BinaryOperator(self,operand,operator.sub,True) + def __rmul__ (self,operand): return BinaryOperator(self,operand,operator.mul,True) + def __rmod__ (self,operand): return BinaryOperator(self,operand,operator.mod,True) + def __rpow__ (self,operand): return BinaryOperator(self,operand,operator.pow,True) + def __rdiv__ (self,operand): return BinaryOperator(self,operand,operator.div,True) + def __rtruediv__ (self,operand): return BinaryOperator(self,operand,operator.truediv,True) + def __rfloordiv__(self,operand): return BinaryOperator(self,operand,operator.floordiv,True) + + def __neg__ (self): return UnaryOperator(self,operator.neg) + def __pos__ (self): return UnaryOperator(self,operator.pos) + def __abs__ (self): return UnaryOperator(self,operator.abs)
+ + +operator_symbols = { + operator.add:'+', + operator.sub:'-', + operator.mul:'*', + operator.mod:'%', + operator.pow:'**', + operator.truediv:'/', + operator.floordiv:'//', + operator.neg:'-', + operator.pos:'+', + operator.abs:'abs', +} + +def pprint(x, *args, **kwargs): + "Pretty-print the provided item, translating operators to their symbols" + return x.pprint(*args, **kwargs) if hasattr(x,'pprint') else operator_symbols.get(x, repr(x)) + + +
[docs]class BinaryOperator(NumberGenerator): + """Applies any binary operator to NumberGenerators or numbers to yield a NumberGenerator.""" + + def __init__(self,lhs,rhs,operator,reverse=False,**args): + """ + Accepts two NumberGenerator operands, an operator, and + optional arguments to be provided to the operator when calling + it on the two operands. + """ + # Note that it's currently not possible to set + # parameters in the superclass when creating an instance, + # because **args is used by this class itself. + super().__init__() + + if reverse: + self.lhs=rhs + self.rhs=lhs + else: + self.lhs=lhs + self.rhs=rhs + self.operator=operator + self.args=args + + def __call__(self): + return self.operator(self.lhs() if callable(self.lhs) else self.lhs, + self.rhs() if callable(self.rhs) else self.rhs, **self.args) + + def pprint(self, *args, **kwargs): + return (pprint(self.lhs, *args, **kwargs) + + pprint(self.operator, *args, **kwargs) + + pprint(self.rhs, *args, **kwargs))
+ + +
[docs]class UnaryOperator(NumberGenerator): + """Applies any unary operator to a NumberGenerator to yield another NumberGenerator.""" + + def __init__(self,operand,operator,**args): + """ + Accepts a NumberGenerator operand, an operator, and + optional arguments to be provided to the operator when calling + it on the operand. + """ + # Note that it's currently not possible to set + # parameters in the superclass when creating an instance, + # because **args is used by this class itself. + super().__init__() + + self.operand=operand + self.operator=operator + self.args=args + + def __call__(self): + return self.operator(self.operand(),**self.args) + + def pprint(self, *args, **kwargs): + return (pprint(self.operator, *args, **kwargs) + '(' + + pprint(self.operand, *args, **kwargs) + ')')
+ + +class Hash: + """ + A platform- and architecture-independent hash function (unlike + Python's inbuilt hash function) for use with an ordered collection + of rationals or integers. + + The supplied name sets the initial hash state. The output from + each call is a 32-bit integer to ensure the value is a regular + Python integer (and not a Python long) on both 32-bit and 64-bit + platforms. This can be important to seed Numpy's random number + generator safely (a bad Numpy bug!). + + The number of inputs (integer or rational numbers) to be supplied + for __call__ must be specified in the constructor and must stay + constant across calls. + """ + def __init__(self, name, input_count): + self.name = name + self.input_count = input_count + self._digest = hashlib.md5() + self._digest.update(name.encode()) + self._hash_struct = struct.Struct( "!" +" ".join(["I"] * (input_count * 2))) + + + def _rational(self, val): + """Convert the given value to a rational, if necessary.""" + + I32 = 4294967296 # Maximum 32 bit unsigned int (i.e. 'I') value + if isinstance(val, int): + numer, denom = val, 1 + elif isinstance(val, fractions.Fraction): + numer, denom = val.numerator, val.denominator + elif hasattr(val, 'numer'): + (numer, denom) = (int(val.numer()), int(val.denom())) + else: + param.main.param.log(param.WARNING, "Casting type '%s' to Fraction.fraction" + % type(val).__name__) + frac = fractions.Fraction(str(val)) + numer, denom = frac.numerator, frac.denominator + return numer % I32, denom % I32 + + + def __getstate__(self): + """ + Avoid Hashlib.md5 TypeError in deepcopy (hashlib issue) + """ + d = self.__dict__.copy() + d.pop('_digest') + d.pop('_hash_struct') + return d + + + def __setstate__(self, d): + self._digest = hashlib.md5() + name, input_count = d['name'], d['input_count'] + self._digest.update(name.encode()) + self._hash_struct = struct.Struct( "!" +" ".join(["I"] * (input_count * 2))) + self.__dict__.update(d) + + + def __call__(self, *vals): + """ + Given integer or rational inputs, generate a cross-platform, + architecture-independent 32-bit integer hash. + """ + # Convert inputs to (numer, denom) pairs with integers + # becoming (int, 1) pairs to match gmpy.mpqs for int values. + pairs = [self._rational(val) for val in vals] + # Unpack pairs and fill struct with ints to update md5 hash + ints = [el for pair in pairs for el in pair] + digest = self._digest.copy() + digest.update(self._hash_struct.pack(*ints)) + # Convert from hex string to 32 bit int + return int(digest.hexdigest()[:7], 16) + + + +class TimeAwareRandomState(TimeAware): + """ + Generic base class to enable time-dependent random + streams. Although this class is the basis of all random numbergen + classes, it is designed to be useful whenever time-dependent + randomness is needed using param's notion of time. For instance, + this class is used by the imagen package to define time-dependent, + random distributions over 2D arrays. + + For generality, this class may use either the Random class from + Python's random module or numpy.random.RandomState. Either of + these random state objects may be used to generate numbers from + any of several different random distributions (e.g. uniform, + Gaussian). The latter offers the ability to generate + multi-dimensional random arrays and more random distributions but + requires numpy as a dependency. + + If declared time_dependent, the random state is fully determined + by a hash value per call. The hash is initialized once with the + object name and then per call using a tuple consisting of the time + (via time_fn) and the global param.random_seed. As a consequence, + for a given name and fixed value of param.random_seed, the random + values generated will be a fixed function of time. + + If the object name has not been set and time_dependent is True, a + message is generated warning that the default object name is + dependent on the order of instantiation. To ensure that the + random number stream will remain constant even if other objects + are added or reordered in your file, supply a unique name + explicitly when you construct the RandomDistribution object. + """ + + # Historically, the default random state was seeded with the tuple + # (500, 500). The CPython implementation implicitly formed an unsigned + # integer seed using the hash of the tuple as in the expression below. Note + # that the resulting integer, and therefore the default initial random + # state, varies across CPython versions (as the hash algorithm has changed) + # and also between 32-bit and 64-bit interpreters. + # + # Seeding based on hashing is deprecated since Python 3.9 and removed in + # Python 3.11; we explicitly continue the historical behavior for the time + # being. + random_generator = param.Parameter( + default=random.Random(c_size_t(hash((500,500))).value), doc= + """ + Random state used by the object. This may be an instance + of random.Random from the Python standard library or an + instance of numpy.random.RandomState. + + This random state may be exclusively owned by the object or + may be shared by all instance of the same class. It is always + possible to give an object its own unique random state by + setting this parameter with a new random state instance. + """) + + __abstract = True + + def _initialize_random_state(self, seed=None, shared=True, name=None): + """ + Initialization method to be called in the constructor of + subclasses to initialize the random state correctly. + + If seed is None, there is no control over the random stream + (no reproducibility of the stream). + + If shared is True (and not time-dependent), the random state + is shared across all objects of the given class. This can be + overridden per object by creating new random state to assign + to the random_generator parameter. + """ + if seed is None: # Equivalent to an uncontrolled seed. + seed = random.Random().randint(0, 1000000) + suffix = '' + else: + suffix = str(seed) + + # If time_dependent, independent state required: otherwise + # time-dependent seeding (via hash) will affect shared + # state. Note that if all objects have time_dependent=True + # shared random state is safe and more memory efficient. + if self.time_dependent or not shared: + self.random_generator = type(self.random_generator)(seed) + + # Seed appropriately (if not shared) + if not shared: + self.random_generator.seed(seed) + + if name is None: + self._verify_constrained_hash() + + hash_name = name if name else self.name + if not shared: hash_name += suffix + self._hashfn = Hash(hash_name, input_count=2) + + if self.time_dependent: + self._hash_and_seed() + + + def _verify_constrained_hash(self): + """ + Warn if the object name is not explicitly set. + """ + changed_params = self.param.values(onlychanged=True) + if self.time_dependent and ('name' not in changed_params): + self.param.log(param.WARNING, "Default object name used to set the seed: " + "random values conditional on object instantiation order.") + + def _hash_and_seed(self): + """ + To be called between blocks of random number generation. A + 'block' can be an unbounded sequence of random numbers so long + as the time value (as returned by time_fn) is guaranteed not + to change within the block. If this condition holds, each + block of random numbers is time-dependent. + + Note: param.random_seed is assumed to be integer or rational. + """ + hashval = self._hashfn(self.time_fn(), param.random_seed) + self.random_generator.seed(hashval) + + + +
[docs]class RandomDistribution(NumberGenerator, TimeAwareRandomState): + """ + The base class for all Numbergenerators using random state. + + Numbergen provides a hierarchy of classes to make it easier to use + the random distributions made available in Python's random module, + where each class is tied to a particular random distribution. + + RandomDistributions support setting parameters on creation rather + than passing them each call, and allow pickling to work properly. + Code that uses these classes will be independent of how many + parameters are used by the underlying distribution, and can simply + treat them as a generic source of random numbers. + + RandomDistributions are examples of TimeAwareRandomState, and thus + can be locked to a global time if desired. By default, + time_dependent=False, and so a new random value will be generated + each time these objects are called. If you have a global time + function, you can set time_dependent=True, so that the random + values will instead be constant at any given time, changing only + when the time changes. Using time_dependent values can help you + obtain fully reproducible streams of random numbers, even if you + e.g. move time forwards and backwards for testing. + + Note: Each RandomDistribution object has independent random state. + """ + + seed = param.Integer(default=None, allow_None=True, doc=""" + Sets the seed of the random number generator and can be used to + randomize time dependent streams. + + If seed is None, there is no control over the random stream + (i.e. no reproducibility of the stream).""") + + __abstract = True + + def __init__(self,**params): + """ + Initialize a new Random() instance and store the supplied + positional and keyword arguments. + + If seed=X is specified, sets the Random() instance's seed. + Otherwise, calls creates an unseeded Random instance which is + likely to result in a state very different from any just used. + """ + super().__init__(**params) + self._initialize_random_state(seed=self.seed, shared=False) + + def __call__(self): + if self.time_dependent: + self._hash_and_seed()
+ + +
[docs]class UniformRandom(RandomDistribution): + """ + Specified with lbound and ubound; when called, return a random + number in the range [lbound, ubound). + + See the random module for further details. + """ + + lbound = param.Number(default=0.0,doc="Inclusive lower bound.") + + ubound = param.Number(default=1.0,doc="Exclusive upper bound.") + + + def __call__(self): + super().__call__() + return self.random_generator.uniform(self.lbound,self.ubound)
+ + + +
[docs]class UniformRandomOffset(RandomDistribution): + """ + Identical to UniformRandom, but specified by mean and range. + When called, return a random number in the range + [mean - range/2, mean + range/2). + + See the random module for further details. + """ + + mean = param.Number(default=0.0, doc="""Mean value""") + + range = param.Number(default=1.0, bounds=(0.0,None), doc=""" + Difference of maximum and minimum value""") + + + def __call__(self): + super().__call__() + return self.random_generator.uniform( + self.mean - self.range / 2.0, + self.mean + self.range / 2.0)
+ + + +
[docs]class UniformRandomInt(RandomDistribution): + """ + Specified with lbound and ubound; when called, return a random + number in the inclusive range [lbound, ubound]. + + See the randint function in the random module for further details. + """ + + lbound = param.Number(default=0,doc="Inclusive lower bound.") + ubound = param.Number(default=1000,doc="Inclusive upper bound.") + + + def __call__(self): + super().__call__() + x = self.random_generator.randint(self.lbound,self.ubound) + return x
+ + + +
[docs]class Choice(RandomDistribution): + """ + Return a random element from the specified list of choices. + + Accepts items of any type, though they are typically numbers. + See the choice() function in the random module for further details. + """ + + choices = param.List(default=[0,1], + doc="List of items from which to select.") + + + def __call__(self): + super().__call__() + return self.random_generator.choice(self.choices)
+ + + +
[docs]class NormalRandom(RandomDistribution): + """ + Normally distributed (Gaussian) random number. + + Specified with mean mu and standard deviation sigma. + See the random module for further details. + """ + + mu = param.Number(default=0.0,doc="Mean value.") + + sigma = param.Number(default=1.0,bounds=(0.0,None),doc="Standard deviation.") + + + def __call__(self): + super().__call__() + return self.random_generator.normalvariate(self.mu,self.sigma)
+ + + +
[docs]class VonMisesRandom(RandomDistribution): + """ + Circularly normal distributed random number. + + If kappa is zero, this distribution reduces to a uniform random + angle over the range 0 to 2*pi. Otherwise, it is concentrated to + a greater or lesser degree (determined by kappa) around the mean + mu. For large kappa (narrow peaks), this distribution approaches + the Gaussian (normal) distribution with variance 1/kappa. See the + random module for further details. + """ + + mu = param.Number(default=0.0,softbounds=(0.0,2*pi),doc=""" + Mean value, typically in the range 0 to 2*pi.""") + + kappa = param.Number(default=1.0,bounds=(0.0,None),softbounds=(0.0,50.0),doc=""" + Concentration (inverse variance).""") + + + def __call__(self): + super().__call__() + return self.random_generator.vonmisesvariate(self.mu,self.kappa)
+ + + + +
[docs]class ScaledTime(NumberGenerator, TimeDependent): + """ + The current time multiplied by some conversion factor. + """ + + factor = param.Number(default=1.0, doc=""" + The factor to be multiplied by the current time value.""") + + + def __call__(self): + return float(self.time_fn() * self.factor)
+ + + +
[docs]class BoxCar(NumberGenerator, TimeDependent): + """ + The boxcar function over the specified time interval. The bounds + are exclusive: zero is returned at the onset time and at the + offset (onset+duration). + + If duration is None, then this reduces to a step function around the + onset value with no offset. + + See http://en.wikipedia.org/wiki/Boxcar_function + """ + + onset = param.Number(0.0, doc="Time of onset.") + + duration = param.Number(None, allow_None=True, bounds=(0.0,None), doc=""" + Duration of step value.""") + + + def __call__(self): + if self.time_fn() <= self.onset: + return 0.0 + elif (self.duration is not None) and (self.time_fn() > self.onset + self.duration): + return 0.0 + else: + return 1.0
+ + + +
[docs]class SquareWave(NumberGenerator, TimeDependent): + """ + Generate a square wave with 'on' periods returning 1.0 and + 'off'periods returning 0.0 of specified duration(s). By default + the portion of time spent in the high state matches the time spent + in the low state (a duty cycle of 50%), but the duty cycle can be + controlled if desired. + + The 'on' state begins after a time specified by the 'onset' + parameter. The onset duration supplied must be less than the off + duration. + """ + + onset = param.Number(0.0, doc="""Time of onset of the first 'on' + state relative to time 0. Must be set to a value less than the + 'off_duration' parameter.""") + + duration = param.Number(1.0, allow_None=False, bounds=(0.0,None), doc=""" + Duration of the 'on' state during which a value of 1.0 is + returned.""") + + off_duration = param.Number(default=None, allow_None=True, + bounds=(0.0,None), doc=""" + Duration of the 'off' value state during which a value of 0.0 + is returned. By default, this duration matches the value of + the 'duration' parameter.""") + + + def __init__(self, **params): + super().__init__(**params) + + if self.off_duration is None: + self.off_duration = self.duration + + if self.onset > self.off_duration: + raise AssertionError("Onset value needs to be less than %s" % self.onset) + + + def __call__(self): + phase_offset = (self.time_fn() - self.onset) % (self.duration + self.off_duration) + if phase_offset < self.duration: + return 1.0 + else: + return 0.0
+ + + +
[docs]class ExponentialDecay(NumberGenerator, TimeDependent): + """ + Function object that provides a value that decays according to an + exponential function, based on a given time function. + + Returns starting_value*base^(-time/time_constant). + + See http://en.wikipedia.org/wiki/Exponential_decay. + """ + + starting_value = param.Number(1.0, doc="Value used for time zero.") + + ending_value = param.Number(0.0, doc="Value used for time infinity.") + + time_constant = param.Number(10000,doc=""" + Time scale for the exponential; large values give slow decay.""") + + base = param.Number(e, doc=""" + Base of the exponent; the default yields starting_value*exp(-t/time_constant). + Another popular choice of base is 2, which allows the + time_constant to be interpreted as a half-life.""") + + + def __call__(self): + Vi = self.starting_value + Vm = self.ending_value + exp = -1.0*float(self.time_fn())/float(self.time_constant) + return Vm + (Vi - Vm) * self.base**exp
+ + + +
[docs]class TimeSampledFn(NumberGenerator, TimeDependent): + """ + Samples the values supplied by a time_dependent callable at + regular intervals of duration 'period', with the sampled value + held constant within each interval. + """ + + period = param.Number(default=1.0, bounds=(0.0,None), + inclusive_bounds=(False,True), softbounds=(0.0,5.0), doc=""" + The periodicity with which the values of fn are sampled.""") + + offset = param.Number(default=0.0, bounds=(0.0,None), + softbounds=(0.0,5.0), doc=""" + The offset from time 0.0 at which the first sample will be drawn. + Must be less than the value of period.""") + + fn = param.Callable(doc=""" + The time-dependent function used to generate the sampled values.""") + + + def __init__(self, **params): + super().__init__(**params) + + if not getattr(self.fn,'time_dependent', False): + raise Exception("The function 'fn' needs to be time dependent.") + + if self.time_fn != self.fn.time_fn: + raise Exception("Objects do not share the same time_fn") + + if self.offset >= self.period: + raise Exception("The onset value must be less than the period.") + + + def __call__(self): + current_time = self.time_fn() + current_time += self.offset + difference = current_time % self.period + with self.time_fn as t: + t(current_time - difference - self.offset) + value = self.fn() + return value
+ + + +
[docs]class BoundedNumber(NumberGenerator): + """ + Function object that silently enforces numeric bounds on values + returned by a callable object. + """ + + generator = param.Callable(None, doc="Object to call to generate values.") + + bounds = param.Parameter((None,None), doc=""" + Legal range for the value returned, as a pair. + + The default bounds are (None,None), meaning there are actually + no bounds. One or both bounds can be set by specifying a + value. For instance, bounds=(None,10) means there is no lower + bound, and an upper bound of 10.""") + + + def __call__(self): + val = self.generator() + min_, max_ = self.bounds + if min_ is not None and val < min_: return min_ + elif max_ is not None and val > max_: return max_ + else: return val
+ + +_public = list({_k for _k,_v in locals().items() if isinstance(_v,type) and issubclass(_v,NumberGenerator)}) +__all__ = _public +
+ +
+ + + +
+ +
+ +
+
+
+ +
+ +
+ +
+ + + + +
+ + +
+
+
+ + + + + + + + \ No newline at end of file diff --git a/_modules/param.html b/_modules/param.html new file mode 100644 index 0000000..005cafc --- /dev/null +++ b/_modules/param.html @@ -0,0 +1,3903 @@ + + + + + + + + + + + param — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +

Source code for param

+"""
+Parameters are a kind of class attribute allowing special behavior,
+including dynamically generated parameter values, documentation
+strings, constant and read-only parameters, and type or range checking
+at assignment time.
+
+Potentially useful for any large Python program that needs
+user-modifiable object attributes; see the Parameter and Parameterized
+classes for more information.  If you do not want to add a dependency
+on external code by importing from a separately installed param
+package, you can simply save this file as param.py and copy it and
+parameterized.py directly into your own package.
+
+This file contains subclasses of Parameter, implementing specific
+parameter types (e.g. Number), and also imports the definition of
+Parameters and Parameterized classes.
+"""
+
+import os.path
+import sys
+import copy
+import glob
+import re
+import datetime as dt
+import collections
+import pathlib
+import typing
+import warnings
+
+from collections import OrderedDict
+from contextlib import contextmanager
+from numbers import Real
+
+from . import version  # noqa: api import
+
+from .depends import depends # noqa: api import
+from .parameterized import (
+    Parameterized, Parameter, String, ParameterizedFunction, ParamOverrides,
+    Undefined, descendents, get_logger, instance_descriptor, dt_types,
+    _int_types
+)
+from .parameterized import (batch_watch, output, script_repr, # noqa: api import
+                            discard_events, edit_constant, instance_descriptor)
+from .parameterized import shared_parameters # noqa: api import
+from .parameterized import logging_level     # noqa: api import
+from .parameterized import DEBUG, VERBOSE, INFO, WARNING, ERROR, CRITICAL # noqa: api import
+from .parameterized import _identity_hook
+from ._utils import (
+    ParamDeprecationWarning as _ParamDeprecationWarning,
+    _deprecate_positional_args,
+    _deprecated,
+    _dict_update,
+    _validate_error_prefix,
+)
+
+# Define '__version__'
+try:
+    # If setuptools_scm is installed (e.g. in a development environment with
+    # an editable install), then use it to determine the version dynamically.
+    from setuptools_scm import get_version
+
+    # This will fail with LookupError if the package is not installed in
+    # editable mode or if Git is not installed.
+    __version__ = get_version(root="..", relative_to=__file__)
+except (ImportError, LookupError):
+    # As a fallback, use the version that is hard-coded in the file.
+    try:
+        from ._version import __version__
+    except ModuleNotFoundError:
+        # The user is probably trying to run this without having installed
+        # the package.
+        __version__ = "0.0.0+unknown"
+
+#: Top-level object to allow messaging not tied to a particular
+#: Parameterized object, as in 'param.main.warning("Invalid option")'.
+main=Parameterized(name="main")
+
+
+# A global random seed (integer or rational) available for controlling
+# the behaviour of Parameterized objects with random state.
+random_seed = 42
+
+
+def _produce_value(value_obj):
+    """
+    A helper function that produces an actual parameter from a stored
+    object: if the object is callable, call it, otherwise return the
+    object.
+    """
+    if callable(value_obj):
+        return value_obj()
+    else:
+        return value_obj
+
+
+# PARAM3_DEPRECATION
+@_deprecated()
+def produce_value(value_obj):
+    """
+    A helper function that produces an actual parameter from a stored
+    object: if the object is callable, call it, otherwise return the
+    object.
+
+    .. deprecated:: 2.0.0
+    """
+    return _produce_value(value_obj)
+
+
+# PARAM3_DEPRECATION
+@_deprecated()
+def as_unicode(obj):
+    """
+    Safely casts any object to unicode including regular string
+    (i.e. bytes) types in python 2.
+
+    .. deprecated:: 2.0.0
+    """
+    return str(obj)
+
+
+# PARAM3_DEPRECATION
+@_deprecated()
+def is_ordered_dict(d):
+    """
+    Predicate checking for ordered dictionaries. OrderedDict is always
+    ordered, and vanilla Python dictionaries are ordered for Python 3.6+
+
+    .. deprecated:: 2.0.0
+    """
+    py3_ordered_dicts = (sys.version_info.major == 3) and (sys.version_info.minor >= 6)
+    vanilla_odicts = (sys.version_info.major > 3) or py3_ordered_dicts
+    return isinstance(d, (OrderedDict)) or (vanilla_odicts and isinstance(d, dict))
+
+
+def _hashable(x):
+    """
+    Return a hashable version of the given object x, with lists and
+    dictionaries converted to tuples.  Allows mutable objects to be
+    used as a lookup key in cases where the object has not actually
+    been mutated. Lookup will fail (appropriately) in cases where some
+    part of the object has changed.  Does not (currently) recursively
+    replace mutable subobjects.
+    """
+    if isinstance(x, collections.abc.MutableSequence):
+        return tuple(x)
+    elif isinstance(x, collections.abc.MutableMapping):
+        return tuple([(k,v) for k,v in x.items()])
+    else:
+        return x
+
+
+# PARAM3_DEPRECATION
+@_deprecated()
+def hashable(x):
+    """
+    Return a hashable version of the given object x, with lists and
+    dictionaries converted to tuples.  Allows mutable objects to be
+    used as a lookup key in cases where the object has not actually
+    been mutated. Lookup will fail (appropriately) in cases where some
+    part of the object has changed.  Does not (currently) recursively
+    replace mutable subobjects.
+
+    .. deprecated:: 2.0.0
+    """
+    return _hashable(x)
+
+
+def _named_objs(objlist, namesdict=None):
+    """
+    Given a list of objects, returns a dictionary mapping from
+    string name for the object to the object itself. Accepts
+    an optional name,obj dictionary, which will override any other
+    name if that item is present in the dictionary.
+    """
+    objs = OrderedDict()
+
+    objtoname = {}
+    unhashables = []
+    if namesdict is not None:
+        for k, v in namesdict.items():
+            try:
+                objtoname[_hashable(v)] = k
+            except TypeError:
+                unhashables.append((k, v))
+
+    for obj in objlist:
+        if objtoname and _hashable(obj) in objtoname:
+            k = objtoname[_hashable(obj)]
+        elif any(obj is v for (_, v) in unhashables):
+            k = [k for (k, v) in unhashables if v is obj][0]
+        elif hasattr(obj, "name"):
+            k = obj.name
+        elif hasattr(obj, '__name__'):
+            k = obj.__name__
+        else:
+            k = str(obj)
+        objs[k] = obj
+    return objs
+
+
+# PARAM3_DEPRECATION
+@_deprecated()
+def named_objs(objlist, namesdict=None):
+    """
+    Given a list of objects, returns a dictionary mapping from
+    string name for the object to the object itself. Accepts
+    an optional name,obj dictionary, which will override any other
+    name if that item is present in the dictionary.
+
+    .. deprecated:: 2.0.0
+    """
+    return _named_objs(objlist, namesdict=namesdict)
+
+
+
[docs]def param_union(*parameterizeds, warn=True): + """ + Given a set of Parameterized objects, returns a dictionary + with the union of all param name,value pairs across them. + + Parameters + ---------- + warn : bool, optional + Wether to warn if the same parameter have been given multiple values, + otherwise use the last value, by default True + + Returns + ------- + dict + Union of all param name,value pairs + """ + d = {} + for o in parameterizeds: + for k in o.param: + if k != 'name': + if k in d and warn: + get_logger().warning(f"overwriting parameter {k}") + d[k] = getattr(o, k) + return d
+ + +
[docs]def guess_param_types(**kwargs): + """ + Given a set of keyword literals, promote to the appropriate + parameter type based on some simple heuristics. + """ + params = {} + for k, v in kwargs.items(): + kws = dict(default=v, constant=True) + if isinstance(v, Parameter): + params[k] = v + elif isinstance(v, dt_types): + params[k] = Date(**kws) + elif isinstance(v, bool): + params[k] = Boolean(**kws) + elif isinstance(v, int): + params[k] = Integer(**kws) + elif isinstance(v, float): + params[k] = Number(**kws) + elif isinstance(v, str): + params[k] = String(**kws) + elif isinstance(v, dict): + params[k] = Dict(**kws) + elif isinstance(v, tuple): + if all(_is_number(el) for el in v): + params[k] = NumericTuple(**kws) + elif all(isinstance(el, dt_types) for el in v) and len(v)==2: + params[k] = DateRange(**kws) + else: + params[k] = Tuple(**kws) + elif isinstance(v, list): + params[k] = List(**kws) + else: + if 'numpy' in sys.modules: + from numpy import ndarray + if isinstance(v, ndarray): + params[k] = Array(**kws) + continue + if 'pandas' in sys.modules: + from pandas import ( + DataFrame as pdDFrame, Series as pdSeries + ) + if isinstance(v, pdDFrame): + params[k] = DataFrame(**kws) + continue + elif isinstance(v, pdSeries): + params[k] = Series(**kws) + continue + params[k] = Parameter(**kws) + + return params
+ + +def parameterized_class(name, params, bases=Parameterized): + """ + Dynamically create a parameterized class with the given name and the + supplied parameters, inheriting from the specified base(s). + """ + if not (isinstance(bases, list) or isinstance(bases, tuple)): + bases=[bases] + return type(name, tuple(bases), params) + + +
[docs]def guess_bounds(params, **overrides): + """ + Given a dictionary of Parameter instances, return a corresponding + set of copies with the bounds appropriately set. + + + If given a set of override keywords, use those numeric tuple bounds. + """ + guessed = {} + for name, p in params.items(): + new_param = copy.copy(p) + if isinstance(p, (Integer, Number)): + if name in overrides: + minv,maxv = overrides[name] + else: + minv, maxv, _ = _get_min_max_value(None, None, value=p.default) + new_param.bounds = (minv, maxv) + guessed[name] = new_param + return guessed
+ + +def _get_min_max_value(min, max, value=None, step=None): + """Return min, max, value given input values with possible None.""" + # Either min and max need to be given, or value needs to be given + if value is None: + if min is None or max is None: + raise ValueError( + f'unable to infer range, value from: ({min}, {max}, {value})' + ) + diff = max - min + value = min + (diff / 2) + # Ensure that value has the same type as diff + if not isinstance(value, type(diff)): + value = min + (diff // 2) + else: # value is not None + if not isinstance(value, Real): + raise TypeError('expected a real number, got: %r' % value) + # Infer min/max from value + if value == 0: + # This gives (0, 1) of the correct type + vrange = (value, value + 1) + elif value > 0: + vrange = (-value, 3*value) + else: + vrange = (3*value, -value) + if min is None: + min = vrange[0] + if max is None: + max = vrange[1] + if step is not None: + # ensure value is on a step + tick = int((value - min) / step) + value = min + tick * step + if not min <= value <= max: + raise ValueError(f'value must be between min and max (min={min}, value={value}, max={max})') + return min, max, value + + +def _deserialize_from_path(ext_to_routine, path, type_name): + """ + Call deserialization routine with path according to extension. + ext_to_routine should be a dictionary mapping each supported + file extension to a corresponding loading function. + """ + if not os.path.isfile(path): + raise FileNotFoundError( + "Could not parse file '{}' as {}: does not exist or is not a file" + "".format(path, type_name)) + root, ext = os.path.splitext(path) + if ext in {'.gz', '.bz2', '.xz', '.zip'}: + # A compressed type. We'll assume the routines can handle such extensions + # transparently (if not, we'll fail later) + ext = os.path.splitext(root)[1] + # FIXME(sdrobert): try...except block below with "raise from" might be a good idea + # once py2.7 support is removed. Provides error + fact that failure occurred in + # deserialization + if ext in ext_to_routine: + return ext_to_routine[ext](path) + raise ValueError( + "Could not parse file '{}' as {}: no deserialization method for files with " + "'{}' extension. Supported extensions: {}" + "".format(path, type_name, ext, ', '.join(sorted(ext_to_routine)))) + + +class Infinity: + """ + An instance of this class represents an infinite value. Unlike + Python's float('inf') value, this object can be safely compared + with gmpy numeric types across different gmpy versions. + + All operators on Infinity() return Infinity(), apart from the + comparison and equality operators. Equality works by checking + whether the two objects are both instances of this class. + """ + + def __eq__ (self,other): return isinstance(other,self.__class__) + def __ne__ (self,other): return not self==other + def __lt__ (self,other): return False + def __le__ (self,other): return False + def __gt__ (self,other): return True + def __ge__ (self,other): return True + def __add__ (self,other): return self + def __radd__(self,other): return self + def __ladd__(self,other): return self + def __sub__ (self,other): return self + def __iadd_ (self,other): return self + def __isub__(self,other): return self + def __repr__(self): return "Infinity()" + def __str__ (self): return repr(self) + + + +class Time(Parameterized): + """ + A callable object returning a number for the current time. + + Here 'time' is an abstract concept that can be interpreted in any + useful way. For instance, in a simulation, it would be the + current simulation time, while in a turn-taking game it could be + the number of moves so far. The key intended usage is to allow + independent Parameterized objects with Dynamic parameters to + remain consistent with a global reference. + + The time datatype (time_type) is configurable, but should + typically be an exact numeric type like an integer or a rational, + so that small floating-point errors do not accumulate as time is + incremented repeatedly. + + When used as a context manager using the 'with' statement + (implemented by the __enter__ and __exit__ special methods), entry + into a context pushes the state of the Time object, allowing the + effect of changes to the time value to be explored by setting, + incrementing or decrementing time as desired. This allows the + state of time-dependent objects to be modified temporarily as a + function of time, within the context's block. For instance, you + could use the context manager to "see into the future" to collect + data over multiple times, without affecting the global time state + once exiting the context. Of course, you need to be careful not to + do anything while in context that would affect the lasting state + of your other objects, if you want things to return to their + starting state when exiting the context. + + The starting time value of a new Time object is 0, converted to + the chosen time type. Here is an illustration of how time can be + manipulated using a Time object: + + >>> time = Time(until=20, timestep=1) + >>> 'The initial time is %s' % time() + 'The initial time is 0' + >>> 'Setting the time to %s' % time(5) + 'Setting the time to 5' + >>> time += 5 + >>> 'After incrementing by 5, the time is %s' % time() + 'After incrementing by 5, the time is 10' + >>> with time as t: # Entering a context + ... 'Time before iteration: %s' % t() + ... 'Iteration: %s' % [val for val in t] + ... 'Time after iteration: %s' % t() + ... t += 2 + ... 'The until parameter may be exceeded outside iteration: %s' % t() + 'Time before iteration: 10' + 'Iteration: [10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]' + 'Time after iteration: 20' + 'The until parameter may be exceeded outside iteration: 22' + >>> 'After exiting the context the time is back to %s' % time() + 'After exiting the context the time is back to 10' + """ + + _infinitely_iterable = True + + forever = Infinity() + + label= String(default='Time', doc=""" + The label given to the Time object. Can be used to convey + more specific notions of time as appropriate. For instance, + the label could be 'Simulation Time' or 'Duration'.""") + + + time_type = Parameter(default=int, constant=True, doc=""" + Callable that Time will use to convert user-specified time + values into the current time; all times will be of the resulting + numeric type. + + By default, time is of integer type, but you can supply any + arbitrary-precision type like a fixed-point decimal or a + rational, to allow fractional times. Floating-point times are + also allowed, but are not recommended because they will suffer + from accumulated rounding errors. For instance, incrementing + a floating-point value 0.0 by 0.05, 20 times, will not reach + 1.0 exactly. Instead, it will be slightly higher than 1.0, + because 0.05 cannot be represented exactly in a standard + floating point numeric type. Fixed-point or rational types + should be able to handle such computations exactly, avoiding + accumulation issues over long time intervals. + + Some potentially useful exact number classes: + + - int: Suitable if all times can be expressed as integers. + + - Python's decimal.Decimal and fractions.Fraction classes: + widely available but slow and also awkward to specify times + (e.g. cannot simply type 0.05, but have to use a special + constructor or a string). + + - fixedpoint.FixedPoint: Allows a natural representation of + times in decimal notation, but very slow and needs to be + installed separately. + + - gmpy.mpq: Allows a natural representation of times in + decimal notation, and very fast because it uses the GNU + Multi-Precision library, but needs to be installed + separately and depends on a non-Python library. gmpy.mpq + is gmpy's rational type. + """) + + timestep = Parameter(default=1.0,doc=""" + Stepsize to be used with the iterator interface. + Time can be advanced or decremented by any value, not just + those corresponding to the stepsize, and so this value is only + a default.""") + + until = Parameter(default=forever,doc=""" + Declaration of an expected end to time values, if any. When + using the iterator interface, iteration will end before this + value is exceeded.""") + + unit = String(default=None, doc=""" + The units of the time dimensions. The default of None is set + as the global time function may on an arbitrary time base. + + Typical values for the parameter are 'seconds' (the SI unit + for time) or subdivisions thereof (e.g. 'milliseconds').""") + + + def __init__(self, **params): + super().__init__(**params) + self._time = self.time_type(0) + self._exhausted = None + self._pushed_state = [] + + + def __eq__(self, other): + if not isinstance(other, Time): + return False + self_params = (self.timestep,self.until) + other_params = (other.timestep,other.until) + if self_params != other_params: + return False + return True + + + def __ne__(self, other): + return not (self == other) + + + def __iter__(self): return self + + + def __next__(self): + timestep = self.time_type(self.timestep) + + if self._exhausted is None: + self._exhausted = False + elif (self._time + timestep) <= self.until: + self._time += timestep + else: + self._exhausted = None + raise StopIteration + return self._time + + def __call__(self, val=None, time_type=None): + """ + When called with no arguments, returns the current time value. + + When called with a specified val, sets the time to it. + + When called with a specified time_type, changes the time_type + and sets the current time to the given val (which *must* be + specified) converted to that time type. To ensure that + the current state remains consistent, this is normally the only + way to change the time_type of an existing Time instance. + """ + + if time_type and val is None: + raise Exception("Please specify a value for the new time_type.") + if time_type: + type_param = self.param.objects('existing').get('time_type') + type_param.constant = False + self.time_type = time_type + type_param.constant = True + if val is not None: + self._time = self.time_type(val) + + return self._time + + + def advance(self, val): + self += val + + + def __iadd__(self, other): + self._time = self._time + self.time_type(other) + return self + + + def __isub__(self, other): + self._time = self._time - self.time_type(other) + return self + + + def __enter__(self): + """Enter the context and push the current state.""" + self._pushed_state.append((self._time, self.timestep, self.until)) + self.in_context = True + return self + + + def __exit__(self, exc, *args): + """ + Exit from the current context, restoring the previous state. + The StopIteration exception raised in context will force the + context to exit. Any other exception exc that is raised in the + block will not be caught. + """ + (self._time, self.timestep, self.until) = self._pushed_state.pop() + self.in_context = len(self._pushed_state) != 0 + if exc is StopIteration: + return True + + + +
[docs]class Dynamic(Parameter): + """ + Parameter whose value can be generated dynamically by a callable + object. + + If a Parameter is declared as Dynamic, it can be set a callable + object (such as a function or callable class), and getting the + parameter's value will call that callable. + + Note that at present, the callable object must allow attributes + to be set on itself. + + If set as time_dependent, setting the Dynamic.time_fn allows the + production of dynamic values to be controlled: a new value will be + produced only if the current value of time_fn is different from + what it was the last time the parameter value was requested. + + By default, the Dynamic parameters are not time_dependent so that + new values are generated on every call regardless of the time. The + default time_fn used when time_dependent is a single Time instance + that allows general manipulations of time. It may be set to some + other callable as required so long as a number is returned on each + call. + """ + + time_fn = Time() + time_dependent = False + + @typing.overload + def __init__( + self, default=None, *, + doc=None, label=None, precedence=None, instantiate=False, constant=False, + readonly=False, pickle_default_value=True, allow_None=False, per_instance=True, + allow_refs=False, nested_refs=False + ): + ... + +
[docs] def __init__(self, default=Undefined, **params): + """ + Call the superclass's __init__ and set instantiate=True if the + default is dynamic. + """ + super().__init__(default=default, **params) + + if callable(self.default): + self._set_instantiate(True) + self._initialize_generator(self.default)
+ + + def _initialize_generator(self,gen,obj=None): + """ + Add 'last time' and 'last value' attributes to the generator. + """ + # Could use a dictionary to hold these things. + if hasattr(obj,"_Dynamic_time_fn"): + gen._Dynamic_time_fn = obj._Dynamic_time_fn + + gen._Dynamic_last = None + # Would have usede None for this, but can't compare a fixedpoint + # number with None (e.g. 1>None but FixedPoint(1)>None can't be done) + gen._Dynamic_time = -1 + + gen._saved_Dynamic_last = [] + gen._saved_Dynamic_time = [] + + + def __get__(self,obj,objtype): + """ + Call the superclass's __get__; if the result is not dynamic + return that result, otherwise ask that result to produce a + value and return it. + """ + gen = super().__get__(obj,objtype) + + if not hasattr(gen,'_Dynamic_last'): + return gen + else: + return self._produce_value(gen) + + + @instance_descriptor + def __set__(self,obj,val): + """ + Call the superclass's set and keep this parameter's + instantiate value up to date (dynamic parameters + must be instantiated). + + If val is dynamic, initialize it as a generator. + """ + super().__set__(obj,val) + + dynamic = callable(val) + if dynamic: self._initialize_generator(val,obj) + if obj is None: self._set_instantiate(dynamic) + + + def _produce_value(self,gen,force=False): + """ + Return a value from gen. + + If there is no time_fn, then a new value will be returned + (i.e. gen will be asked to produce a new value). + + If force is True, or the value of time_fn() is different from + what it was was last time _produce_value was called, a new + value will be produced and returned. Otherwise, the last value + gen produced will be returned. + """ + + if hasattr(gen,"_Dynamic_time_fn"): + time_fn = gen._Dynamic_time_fn + else: + time_fn = self.time_fn + + if (time_fn is None) or (not self.time_dependent): + value = _produce_value(gen) + gen._Dynamic_last = value + else: + + time = time_fn() + + if force or time!=gen._Dynamic_time: + value = _produce_value(gen) + gen._Dynamic_last = value + gen._Dynamic_time = time + else: + value = gen._Dynamic_last + + return value + + + def _value_is_dynamic(self,obj,objtype=None): + """ + Return True if the parameter is actually dynamic (i.e. the + value is being generated). + """ + return hasattr(super().__get__(obj,objtype),'_Dynamic_last') + + + def _inspect(self,obj,objtype=None): + """Return the last generated value for this parameter.""" + gen=super().__get__(obj,objtype) + + if hasattr(gen,'_Dynamic_last'): + return gen._Dynamic_last + else: + return gen + + + def _force(self,obj,objtype=None): + """Force a new value to be generated, and return it.""" + gen=super().__get__(obj,objtype) + + if hasattr(gen,'_Dynamic_last'): + return self._produce_value(gen,force=True) + else: + return gen
+ + +import numbers +def _is_number(obj): + if isinstance(obj, numbers.Number): return True + # The extra check is for classes that behave like numbers, such as those + # found in numpy, gmpy, etc. + elif (hasattr(obj, '__int__') and hasattr(obj, '__add__')): return True + # This is for older versions of gmpy + elif hasattr(obj, 'qdiv'): return True + else: return False + + +
[docs]def get_soft_bounds(bounds, softbounds): + """ + For each soft bound (upper and lower), if there is a defined bound + (not equal to None) and does not exceed the hard bound, then it is + returned. Otherwise it defaults to the hard bound. The hard bound + could still be None. + """ + if bounds is None: + hl, hu = (None, None) + else: + hl, hu = bounds + + if softbounds is None: + sl, su = (None, None) + else: + sl, su = softbounds + + if sl is None or (hl is not None and sl<hl): + l = hl + else: + l = sl + + if su is None or (hu is not None and su>hu): + u = hu + else: + u = su + + return (l, u)
+ + +
[docs]class Bytes(Parameter): + """ + A Bytes Parameter, with a default value and optional regular + expression (regex) matching. + + Similar to the String parameter, but instead of type string + this parameter only allows objects of type bytes (e.g. b'bytes'). + """ + + __slots__ = ['regex'] + + _slot_defaults = _dict_update( + Parameter._slot_defaults, default=b"", regex=None, allow_None=False, + ) + + + @typing.overload + def __init__( + self, + default=b"", *, regex=None, allow_None=False, + doc=None, label=None, precedence=None, instantiate=False, + constant=False, readonly=False, pickle_default_value=True, per_instance=True, + allow_refs=False, nested_refs=False + ): + ... + +
[docs] @_deprecate_positional_args + def __init__(self, default=Undefined, *, regex=Undefined, allow_None=Undefined, **kwargs): + super().__init__(default=default, **kwargs) + self.regex = regex + self._validate(self.default)
+ + def _validate_regex(self, val, regex): + if (val is None and self.allow_None): + return + if regex is not None and re.match(regex, val) is None: + raise ValueError( + f"{_validate_error_prefix(self)} value {val!r} " + f"does not match regex {regex!r}." + ) + + def _validate_value(self, val, allow_None): + if allow_None and val is None: + return + if not isinstance(val, bytes): + raise ValueError( + f"{_validate_error_prefix(self)} only takes a byte string value, " + f"not value of {type(val)}." + ) + + def _validate(self, val): + self._validate_value(val, self.allow_None) + self._validate_regex(val, self.regex)
+ + +class __compute_set_hook: + """Remove when set_hook is removed""" + def __call__(self, p): + return _identity_hook + + def __repr__(self): + return repr(self.sig) + + @property + def sig(self): + return None + + +_compute_set_hook = __compute_set_hook() + + +
[docs]class Number(Dynamic): + """ + A numeric Dynamic Parameter, with a default value and optional bounds. + + There are two types of bounds: ``bounds`` and + ``softbounds``. ``bounds`` are hard bounds: the parameter must + have a value within the specified range. The default bounds are + (None,None), meaning there are actually no hard bounds. One or + both bounds can be set by specifying a value + (e.g. bounds=(None,10) means there is no lower bound, and an upper + bound of 10). Bounds are inclusive by default, but exclusivity + can be specified for each bound by setting inclusive_bounds + (e.g. inclusive_bounds=(True,False) specifies an exclusive upper + bound). + + Number is also a type of Dynamic parameter, so its value + can be set to a callable to get a dynamically generated + number (see Dynamic). + + When not being dynamically generated, bounds are checked when a + Number is created or set. Using a default value outside the hard + bounds, or one that is not numeric, results in an exception. When + being dynamically generated, bounds are checked when the value + of a Number is requested. A generated value that is not numeric, + or is outside the hard bounds, results in an exception. + + As a special case, if allow_None=True (which is true by default if + the parameter has a default of None when declared) then a value + of None is also allowed. + + A separate function set_in_bounds() is provided that will + silently crop the given value into the legal range, for use + in, for instance, a GUI. + + ``softbounds`` are present to indicate the typical range of + the parameter, but are not enforced. Setting the soft bounds + allows, for instance, a GUI to know what values to display on + sliders for the Number. + + Example of creating a Number:: + + AB = Number(default=0.5, bounds=(None,10), softbounds=(0,1), doc='Distance from A to B.') + + """ + + __slots__ = ['bounds', 'softbounds', 'inclusive_bounds', 'set_hook', 'step'] + + _slot_defaults = _dict_update( + Dynamic._slot_defaults, default=0.0, bounds=None, softbounds=None, + inclusive_bounds=(True,True), step=None, set_hook=_compute_set_hook, + ) + + @typing.overload + def __init__( + self, + default=0.0, *, bounds=None, softbounds=None, inclusive_bounds=(True,True), step=None, set_hook=None, + allow_None=False, doc=None, label=None, precedence=None, instantiate=False, + constant=False, readonly=False, pickle_default_value=True, per_instance=True, + allow_refs=False, nested_refs=False + ): + ... + +
[docs] @_deprecate_positional_args + def __init__(self, default=Undefined, *, bounds=Undefined, softbounds=Undefined, + inclusive_bounds=Undefined, step=Undefined, set_hook=Undefined, **params): + """ + Initialize this parameter object and store the bounds. + + Non-dynamic default values are checked against the bounds. + """ + super().__init__(default=default, **params) + self.set_hook = set_hook + self.bounds = bounds + self.inclusive_bounds = inclusive_bounds + self.softbounds = softbounds + self.step = step + self._validate(self.default)
+ + def __get__(self, obj, objtype): + """ + Same as the superclass's __get__, but if the value was + dynamically generated, check the bounds. + """ + result = super().__get__(obj, objtype) + + # Should be able to optimize this commonly used method by + # avoiding extra lookups (e.g. _value_is_dynamic() is also + # looking up 'result' - should just pass it in). + if self._value_is_dynamic(obj, objtype): + self._validate(result) + return result + + def set_in_bounds(self,obj,val): + """ + Set to the given value, but cropped to be within the legal bounds. + All objects are accepted, and no exceptions will be raised. See + crop_to_bounds for details on how cropping is done. + """ + if not callable(val): + bounded_val = self.crop_to_bounds(val) + else: + bounded_val = val + super().__set__(obj, bounded_val) + + def crop_to_bounds(self, val): + """ + Return the given value cropped to be within the hard bounds + for this parameter. + + If a numeric value is passed in, check it is within the hard + bounds. If it is larger than the high bound, return the high + bound. If it's smaller, return the low bound. In either case, the + returned value could be None. If a non-numeric value is passed + in, set to be the default value (which could be None). In no + case is an exception raised; all values are accepted. + + As documented in https://github.com/holoviz/param/issues/80, + currently does not respect exclusive bounds, which would + strictly require setting to one less for integer values or + an epsilon less for floats. + """ + # Values outside the bounds are silently cropped to + # be inside the bounds. + if _is_number(val): + if self.bounds is None: + return val + vmin, vmax = self.bounds + if vmin is not None: + if val < vmin: + return vmin + + if vmax is not None: + if val > vmax: + return vmax + + elif self.allow_None and val is None: + return val + + else: + # non-numeric value sent in: reverts to default value + return self.default + + return val + + def _validate_bounds(self, val, bounds, inclusive_bounds): + if bounds is None or (val is None and self.allow_None) or callable(val): + return + vmin, vmax = bounds + incmin, incmax = inclusive_bounds + if vmax is not None: + if incmax is True: + if not val <= vmax: + raise ValueError( + f"{_validate_error_prefix(self)} must be at most " + f"{vmax}, not {val}." + ) + else: + if not val < vmax: + raise ValueError( + f"{_validate_error_prefix(self)} must be less than " + f"{vmax}, not {val}." + ) + + if vmin is not None: + if incmin is True: + if not val >= vmin: + raise ValueError( + f"{_validate_error_prefix(self)} must be at least " + f"{vmin}, not {val}." + ) + else: + if not val > vmin: + raise ValueError( + f"{_validate_error_prefix(self)} must be greater than " + f"{vmin}, not {val}." + ) + + def _validate_value(self, val, allow_None): + if (allow_None and val is None) or callable(val): + return + + if not _is_number(val): + raise ValueError( + f"{_validate_error_prefix(self)} only takes numeric values, " + f"not {type(val)}." + ) + + def _validate_step(self, val, step): + if step is not None and not _is_number(step): + raise ValueError( + f"{_validate_error_prefix(self, 'step')} can only be " + f"None or a numeric value, not {type(step)}." + ) + + def _validate(self, val): + """ + Checks that the value is numeric and that it is within the hard + bounds; if not, an exception is raised. + """ + self._validate_value(val, self.allow_None) + self._validate_step(val, self.step) + self._validate_bounds(val, self.bounds, self.inclusive_bounds) + + def get_soft_bounds(self): + return get_soft_bounds(self.bounds, self.softbounds) + + def __setstate__(self,state): + if 'step' not in state: + state['step'] = None + + super().__setstate__(state)
+ + + +
[docs]class Integer(Number): + """Numeric Parameter required to be an Integer""" + + _slot_defaults = _dict_update(Number._slot_defaults, default=0) + + def _validate_value(self, val, allow_None): + if callable(val): + return + + if allow_None and val is None: + return + + if not isinstance(val, _int_types): + raise ValueError( + f"{_validate_error_prefix(self)} must be an integer, " + f"not {type(val)}." + ) + + def _validate_step(self, val, step): + if step is not None and not isinstance(step, int): + raise ValueError( + f"{_validate_error_prefix(self, 'step')} can only be " + f"None or an integer value, not {type(step)}." + )
+ + + +
[docs]class Magnitude(Number): + """Numeric Parameter required to be in the range [0.0-1.0].""" + + _slot_defaults = _dict_update(Number._slot_defaults, default=1.0, bounds=(0.0,1.0)) + + @typing.overload + def __init__( + self, + default=1.0, *, bounds=(0.0, 1.0), softbounds=None, inclusive_bounds=(True,True), step=None, set_hook=None, + allow_None=False, doc=None, label=None, precedence=None, instantiate=False, + constant=False, readonly=False, pickle_default_value=True, per_instance=True, + allow_refs=False, nested_refs=False + ): + ... + +
[docs] def __init__(self, default=Undefined, *, bounds=Undefined, softbounds=Undefined, + inclusive_bounds=Undefined, step=Undefined, set_hook=Undefined, **params): + super().__init__( + default=default, bounds=bounds, softbounds=softbounds, + inclusive_bounds=inclusive_bounds, step=step, set_hook=set_hook, **params + )
+ + +
[docs]class Boolean(Parameter): + """Binary or tristate Boolean Parameter.""" + + _slot_defaults = _dict_update(Parameter._slot_defaults, default=False) + + @typing.overload + def __init__( + self, + default=False, *, + allow_None=False, doc=None, label=None, precedence=None, instantiate=False, + constant=False, readonly=False, pickle_default_value=True, per_instance=True, + allow_refs=False, nested_refs=False + ): + ... + +
[docs] @_deprecate_positional_args + def __init__(self, default=Undefined, **params): + super().__init__(default=default, **params) + self._validate(self.default)
+ + def _validate_value(self, val, allow_None): + if allow_None: + if not isinstance(val, bool) and val is not None: + raise ValueError( + f"{_validate_error_prefix(self)} only takes a " + f"boolean value or None, not {val!r}." + ) + elif not isinstance(val, bool): + raise ValueError( + f"{_validate_error_prefix(self)} must be True or False, " + f"not {val!r}." + ) + + def _validate(self, val): + self._validate_value(val, self.allow_None)
+ + +class __compute_length_of_default: + def __call__(self, p): + return len(p.default) + + def __repr__(self): + return repr(self.sig) + + @property + def sig(self): + return None + + +_compute_length_of_default = __compute_length_of_default() + + +
[docs]class Tuple(Parameter): + """A tuple Parameter (e.g. ('a',7.6,[3,5])) with a fixed tuple length.""" + + __slots__ = ['length'] + + _slot_defaults = _dict_update(Parameter._slot_defaults, default=(0,0), length=_compute_length_of_default) + + @typing.overload + def __init__( + self, + default=(0,0), *, length=None, + doc=None, label=None, precedence=None, instantiate=False, constant=False, + readonly=False, pickle_default_value=True, allow_None=False, per_instance=True, + allow_refs=False, nested_refs=False + ): + ... + +
[docs] @_deprecate_positional_args + def __init__(self, default=Undefined, *, length=Undefined, **params): + """ + Initialize a tuple parameter with a fixed length (number of + elements). The length is determined by the initial default + value, if any, and must be supplied explicitly otherwise. The + length is not allowed to change after instantiation. + """ + super().__init__(default=default, **params) + if length is Undefined and self.default is None: + raise ValueError( + f"{_validate_error_prefix(self, 'length')} must be " + "specified if no default is supplied." + ) + elif default is not Undefined and default: + self.length = len(default) + else: + self.length = length + self._validate(self.default)
+ + def _validate_value(self, val, allow_None): + if val is None and allow_None: + return + + if not isinstance(val, tuple): + raise ValueError( + f"{_validate_error_prefix(self)} only takes a tuple value, " + f"not {type(val)}." + ) + + def _validate_length(self, val, length): + if val is None and self.allow_None: + return + + if not len(val) == length: + raise ValueError( + f"{_validate_error_prefix(self, 'length')} is not " + f"of the correct length ({len(val)} instead of {length})." + ) + + def _validate(self, val): + self._validate_value(val, self.allow_None) + self._validate_length(val, self.length) + + @classmethod + def serialize(cls, value): + if value is None: + return None + return list(value) # As JSON has no tuple representation + + @classmethod + def deserialize(cls, value): + if value == 'null' or value is None: + return None + return tuple(value) # As JSON has no tuple representation
+ + +
[docs]class NumericTuple(Tuple): + """A numeric tuple Parameter (e.g. (4.5,7.6,3)) with a fixed tuple length.""" + + def _validate_value(self, val, allow_None): + super()._validate_value(val, allow_None) + if allow_None and val is None: + return + for n in val: + if _is_number(n): + continue + raise ValueError( + f"{_validate_error_prefix(self)} only takes numeric " + f"values, not {type(n)}." + )
+ + +
[docs]class XYCoordinates(NumericTuple): + """A NumericTuple for an X,Y coordinate.""" + + _slot_defaults = _dict_update(NumericTuple._slot_defaults, default=(0.0, 0.0)) + + @typing.overload + def __init__( + self, + default=(0.0, 0.0), *, length=None, + allow_None=False, doc=None, label=None, precedence=None, instantiate=False, + constant=False, readonly=False, pickle_default_value=True, per_instance=True, + allow_refs=False, nested_refs=False + ): + ... + +
[docs] def __init__(self, default=Undefined, **params): + super().__init__(default=default, length=2, **params)
+ + +
[docs]class Callable(Parameter): + """ + Parameter holding a value that is a callable object, such as a function. + + A keyword argument instantiate=True should be provided when a + function object is used that might have state. On the other hand, + regular standalone functions cannot be deepcopied as of Python + 2.4, so instantiate must be False for those values. + """ + + @typing.overload + def __init__( + self, + default=None, *, + allow_None=False, doc=None, label=None, precedence=None, instantiate=False, + constant=False, readonly=False, pickle_default_value=True, per_instance=True, + allow_refs=False, nested_refs=False + ): + ... + +
[docs] @_deprecate_positional_args + def __init__(self, default=Undefined, **params): + super().__init__(default=default, **params) + self._validate(self.default)
+ + def _validate_value(self, val, allow_None): + if (allow_None and val is None) or callable(val): + return + raise ValueError( + f"{_validate_error_prefix(self)} only takes a callable object, " + f"not objects of {type(val)}." + ) + + def _validate(self, val): + self._validate_value(val, self.allow_None)
+ + +
[docs]class Action(Callable): + """ + A user-provided function that can be invoked like a class or object method using (). + In a GUI, this might be mapped to a button, but it can be invoked directly as well. + """
+# Currently same implementation as Callable, but kept separate to allow different handling in GUIs + + +def _is_abstract(class_): + try: + return class_.abstract + except AttributeError: + return False + + +# Could be a method of ClassSelector. +
[docs]def concrete_descendents(parentclass): + """ + Return a dictionary containing all subclasses of the specified + parentclass, including the parentclass. Only classes that are + defined in scripts that have been run or modules that have been + imported are included, so the caller will usually first do ``from + package import *``. + + Only non-abstract classes will be included. + """ + return {c.__name__:c for c in descendents(parentclass) + if not _is_abstract(c)}
+ + +
[docs]class Composite(Parameter): + """ + A Parameter that is a composite of a set of other attributes of the class. + + The constructor argument 'attribs' takes a list of attribute + names, which may or may not be Parameters. Getting the parameter + returns a list of the values of the constituents of the composite, + in the order specified. Likewise, setting the parameter takes a + sequence of values and sets the value of the constituent + attributes. + + This Parameter type has not been tested with watchers and + dependencies, and may not support them properly. + """ + + __slots__ = ['attribs', 'objtype'] + + @typing.overload + def __init__( + self, + *, attribs=None, + allow_None=False, doc=None, label=None, precedence=None, instantiate=False, + constant=False, readonly=False, pickle_default_value=True, per_instance=True, + allow_refs=False, nested_refs=False + ): + ... + +
[docs] @_deprecate_positional_args + def __init__(self, *, attribs=Undefined, **kw): + if attribs is Undefined: + attribs = [] + super().__init__(default=Undefined, **kw) + self.attribs = attribs
+ + def __get__(self, obj, objtype): + """ + Return the values of all the attribs, as a list. + """ + if obj is None: + return [getattr(objtype, a) for a in self.attribs] + else: + return [getattr(obj, a) for a in self.attribs] + + def _validate_attribs(self, val, attribs): + if len(val) == len(attribs): + return + raise ValueError( + f"{_validate_error_prefix(self)} got the wrong number " + f"of values (needed {len(attribs)}, but got {len(val)})." + ) + + def _validate(self, val): + self._validate_attribs(val, self.attribs) + + def _post_setter(self, obj, val): + if obj is None: + for a, v in zip(self.attribs, val): + setattr(self.objtype, a, v) + else: + for a, v in zip(self.attribs, val): + setattr(obj, a, v)
+ + +class SelectorBase(Parameter): + """ + Parameter whose value must be chosen from a list of possibilities. + + Subclasses must implement get_range(). + """ + + __abstract = True + + def get_range(self): + raise NotImplementedError("get_range() must be implemented in subclasses.") + + +class ListProxy(list): + """ + Container that supports both list-style and dictionary-style + updates. Useful for replacing code that originally accepted lists + but needs to support dictionary access (typically for naming + items). + """ + + def __init__(self, iterable, parameter=None): + super().__init__(iterable) + self._parameter = parameter + + def _warn(self, method): + clsname = type(self._parameter).__name__ + get_logger().warning( + '{clsname}.objects{method} is deprecated if objects attribute ' + 'was declared as a dictionary. Use `{clsname}.objects[label] ' + '= value` instead.'.format(clsname=clsname, method=method) + ) + + @contextmanager + def _trigger(self, trigger=True): + trigger = 'objects' in self._parameter.watchers and trigger + old = dict(self._parameter.names) or list(self._parameter._objects) + yield + if trigger: + value = self._parameter.names or self._parameter._objects + self._parameter._trigger_event('objects', old, value) + + def __getitem__(self, index): + if self._parameter.names: + return self._parameter.names[index] + return super().__getitem__(index) + + def __setitem__(self, index, object, trigger=True): + if isinstance(index, (int, slice)): + if self._parameter.names: + self._warn('[index] = object') + with self._trigger(): + super().__setitem__(index, object) + self._parameter._objects[index] = object + return + if self and not self._parameter.names: + self._parameter.names = _named_objs(self) + with self._trigger(trigger): + if index in self._parameter.names: + old = self._parameter.names[index] + idx = self.index(old) + super().__setitem__(idx, object) + self._parameter._objects[idx] = object + else: + super().append(object) + self._parameter._objects.append(object) + self._parameter.names[index] = object + + def __eq__(self, other): + eq = super().__eq__(other) + if self._parameter.names and eq is NotImplemented: + return dict(zip(self._parameter.names, self)) == other + return eq + + def __ne__(self, other): + return not self.__eq__(other) + + def append(self, object): + if self._parameter.names: + self._warn('.append') + with self._trigger(): + super().append(object) + self._parameter._objects.append(object) + + def copy(self): + if self._parameter.names: + return self._parameter.names.copy() + return list(self) + + def clear(self): + with self._trigger(): + super().clear() + self._parameter._objects.clear() + self._parameter.names.clear() + + def extend(self, objects): + if self._parameter.names: + self._warn('.append') + with self._trigger(): + super().extend(objects) + self._parameter._objects.extend(objects) + + def get(self, key, default=None): + if self._parameter.names: + return self._parameter.names.get(key, default) + return _named_objs(self).get(key, default) + + def insert(self, index, object): + if self._parameter.names: + self._warn('.insert') + with self._trigger(): + super().insert(index, object) + self._parameter._objects.insert(index, object) + + def items(self): + if self._parameter.names: + return self._parameter.names.items() + return _named_objs(self).items() + + def keys(self): + if self._parameter.names: + return self._parameter.names.keys() + return _named_objs(self).keys() + + def pop(self, *args): + index = args[0] if args else -1 + if isinstance(index, int): + with self._trigger(): + super().pop(index) + object = self._parameter._objects.pop(index) + if self._parameter.names: + self._parameter.names = { + k: v for k, v in self._parameter.names.items() + if v is object + } + return + if self and not self._parameter.names: + raise ValueError( + 'Cannot pop an object from {clsname}.objects if ' + 'objects was not declared as a dictionary.' + ) + with self._trigger(): + object = self._parameter.names.pop(*args) + super().remove(object) + self._parameter._objects.remove(object) + return object + + def remove(self, object): + with self._trigger(): + super().remove(object) + self._parameter._objects.remove(object) + if self._parameter.names: + copy = self._parameter.names.copy() + self._parameter.names.clear() + self._parameter.names.update({ + k: v for k, v in copy.items() if v is not object + }) + + def update(self, objects, **items): + if not self._parameter.names: + self._parameter.names = _named_objs(self) + objects = objects.items() if isinstance(objects, dict) else objects + with self._trigger(): + for i, o in enumerate(objects): + if not isinstance(o, collections.abc.Sequence): + raise TypeError( + f'cannot convert dictionary update sequence element #{i} to a sequence' + ) + o = tuple(o) + n = len(o) + if n != 2: + raise ValueError( + f'dictionary update sequence element #{i} has length {n}; 2 is required' + ) + k, v = o + self.__setitem__(k, v, trigger=False) + for k, v in items.items(): + self.__setitem__(k, v, trigger=False) + + def values(self): + if self._parameter.names: + return self._parameter.names.values() + return _named_objs(self).values() + + +class __compute_selector_default: + """ + Using a function instead of setting default to [] in _slot_defaults, as + if it were modified in place later, which would happen with check_on_set set to False, + then the object in _slot_defaults would itself be updated and the next Selector + instance created wouldn't have [] as the default but a populated list. + """ + def __call__(self, p): + return [] + + def __repr__(self): + return repr(self.sig) + + @property + def sig(self): + return [] + +_compute_selector_default = __compute_selector_default() + + +class __compute_selector_checking_default: + def __call__(self, p): + return len(p.objects) != 0 + + def __repr__(self): + return repr(self.sig) + + @property + def sig(self): + return None + +_compute_selector_checking_default = __compute_selector_checking_default() + + +class _SignatureSelector(Parameter): + # Needs docstring; why is this a separate mixin? + _slot_defaults = _dict_update( + SelectorBase._slot_defaults, _objects=_compute_selector_default, + compute_default_fn=None, check_on_set=_compute_selector_checking_default, + allow_None=None, instantiate=False, default=None, + ) + + @classmethod + def _modified_slots_defaults(cls): + defaults = super()._modified_slots_defaults() + defaults['objects'] = defaults.pop('_objects') + return defaults + + +
[docs]class Selector(SelectorBase, _SignatureSelector): + """ + Parameter whose value must be one object from a list of possible objects. + + By default, if no default is specified, picks the first object from + the provided set of objects, as long as the objects are in an + ordered data collection. + + check_on_set restricts the value to be among the current list of + objects. By default, if objects are initially supplied, + check_on_set is True, whereas if no objects are initially + supplied, check_on_set is False. This can be overridden by + explicitly specifying check_on_set initially. + + If check_on_set is True (either because objects are supplied + initially, or because it is explicitly specified), the default + (initial) value must be among the list of objects (unless the + default value is None). + + The list of objects can be supplied as a list (appropriate for + selecting among a set of strings, or among a set of objects with a + "name" parameter), or as a (preferably ordered) dictionary from + names to objects. If a dictionary is supplied, the objects + will need to be hashable so that their names can be looked + up from the object value. + + empty_default is an internal argument that does not have a slot. + """ + + __slots__ = ['_objects', 'compute_default_fn', 'check_on_set', 'names'] + + @typing.overload + def __init__( + self, + *, objects=[], default=None, instantiate=False, compute_default_fn=None, + check_on_set=None, allow_None=None, empty_default=False, + doc=None, label=None, precedence=None, constant=False, readonly=False, + pickle_default_value=True, per_instance=True, allow_refs=False, nested_refs=False + ): + ... + + # Selector is usually used to allow selection from a list of + # existing objects, therefore instantiate is False by default. +
[docs] @_deprecate_positional_args + def __init__(self, *, objects=Undefined, default=Undefined, instantiate=Undefined, + compute_default_fn=Undefined, check_on_set=Undefined, + allow_None=Undefined, empty_default=False, **params): + + autodefault = Undefined + if objects is not Undefined and objects: + if isinstance(objects, dict): + autodefault = list(objects.values())[0] + elif isinstance(objects, list): + autodefault = objects[0] + + default = autodefault if (not empty_default and default is Undefined) else default + + self.objects = objects + self.compute_default_fn = compute_default_fn + self.check_on_set = check_on_set + + super().__init__( + default=default, instantiate=instantiate, **params) + # Required as Parameter sets allow_None=True if default is None + if allow_None is Undefined: + self.allow_None = self._slot_defaults['allow_None'] + else: + self.allow_None = allow_None + if self.default is not None: + self._validate_value(self.default) + self._update_state()
+ + def _update_state(self): + if self.check_on_set is False and self.default is not None: + self._ensure_value_is_in_objects(self.default) + + @property + def objects(self): + return ListProxy(self._objects, self) + + @objects.setter + def objects(self, objects): + if isinstance(objects, collections.abc.Mapping): + self.names = objects + self._objects = list(objects.values()) + else: + self.names = {} + self._objects = objects + + # Note that if the list of objects is changed, the current value for + # this parameter in existing POs could be outside of the new range. + + def compute_default(self): + """ + If this parameter's compute_default_fn is callable, call it + and store the result in self.default. + + Also removes None from the list of objects (if the default is + no longer None). + """ + if self.default is None and callable(self.compute_default_fn): + self.default = self.compute_default_fn() + self._ensure_value_is_in_objects(self.default) + + def _validate(self, val): + if not self.check_on_set: + self._ensure_value_is_in_objects(val) + return + + self._validate_value(val) + + def _validate_value(self, val): + if self.check_on_set and not (self.allow_None and val is None) and val not in self.objects: + items = [] + limiter = ']' + length = 0 + for item in self.objects: + string = str(item) + length += len(string) + if length < 200: + items.append(string) + else: + limiter = ', ...]' + break + items = '[' + ', '.join(items) + limiter + raise ValueError( + f"{_validate_error_prefix(self)} does not accept {val!r}; " + f"valid options include: {items!r}" + ) + + def _ensure_value_is_in_objects(self, val): + """ + Make sure that the provided value is present on the objects list. + Subclasses can override if they support multiple items on a list, + to check each item instead. + """ + if not (val in self.objects): + self._objects.append(val) + + def get_range(self): + """ + Return the possible objects to which this parameter could be set. + + (Returns the dictionary {object.name: object}.) + """ + return _named_objs(self._objects, self.names)
+ + +class ObjectSelector(Selector): + """ + Deprecated. Same as Selector, but with a different constructor for + historical reasons. + """ + + @typing.overload + def __init__( + self, + default=None, *, objects=[], instantiate=False, compute_default_fn=None, + check_on_set=None, allow_None=None, empty_default=False, + doc=None, label=None, precedence=None, constant=False, readonly=False, + pickle_default_value=True, per_instance=True, allow_refs=False, nested_refs=False + ): + ... + + @_deprecate_positional_args + def __init__(self, default=Undefined, *, objects=Undefined, **kwargs): + super().__init__(objects=objects, default=default, + empty_default=True, **kwargs) + + +
[docs]class ClassSelector(SelectorBase): + """ + Parameter allowing selection of either a subclass or an instance of a given set of classes. + By default, requires an instance, but if is_instance=False, accepts a class instead. + Both class and instance values respect the instantiate slot, though it matters only + for is_instance=True. + """ + + __slots__ = ['class_', 'is_instance'] + + _slot_defaults = _dict_update(SelectorBase._slot_defaults, instantiate=True, is_instance=True) + + @typing.overload + def __init__( + self, + *, class_, default=None, instantiate=True, is_instance=True, + allow_None=False, doc=None, label=None, precedence=None, + constant=False, readonly=False, pickle_default_value=True, per_instance=True, + allow_refs=False, nested_refs=False + ): + ... + +
[docs] @_deprecate_positional_args + def __init__(self, *, class_, default=Undefined, instantiate=Undefined, is_instance=Undefined, **params): + self.class_ = class_ + self.is_instance = is_instance + super().__init__(default=default,instantiate=instantiate,**params) + self._validate(self.default)
+ + def _validate(self, val): + super()._validate(val) + self._validate_class_(val, self.class_, self.is_instance) + + def _validate_class_(self, val, class_, is_instance): + if (val is None and self.allow_None): + return + if isinstance(class_, tuple): + class_name = ('(%s)' % ', '.join(cl.__name__ for cl in class_)) + else: + class_name = class_.__name__ + if is_instance: + if not (isinstance(val, class_)): + raise ValueError( + f"{_validate_error_prefix(self)} value must be an instance of {class_name}, not {val!r}.") + else: + if not (issubclass(val, class_)): + raise ValueError( + f"{_validate_error_prefix(self)} value must be a subclass of {class_name}, not {val}.") + + def get_range(self): + """ + Return the possible types for this parameter's value. + + (I.e. return `{name: <class>}` for all classes that are + concrete_descendents() of `self.class_`.) + + Only classes from modules that have been imported are added + (see concrete_descendents()). + """ + classes = self.class_ if isinstance(self.class_, tuple) else (self.class_,) + all_classes = {} + for cls in classes: + all_classes.update(concrete_descendents(cls)) + d = OrderedDict((name, class_) for name,class_ in all_classes.items()) + if self.allow_None: + d['None'] = None + return d
+ + +
[docs]class List(Parameter): + """ + Parameter whose value is a list of objects, usually of a specified type. + + The bounds allow a minimum and/or maximum length of + list to be enforced. If the item_type is non-None, all + items in the list are checked to be of that type. + + `class_` is accepted as an alias for `item_type`, but is + deprecated due to conflict with how the `class_` slot is + used in Selector classes. + """ + + __slots__ = ['bounds', 'item_type', 'class_'] + + _slot_defaults = _dict_update( + Parameter._slot_defaults, class_=None, item_type=None, bounds=(0, None), + instantiate=True, default=[], + ) + + @typing.overload + def __init__( + self, + default=[], *, class_=None, item_type=None, instantiate=True, bounds=(0, None), + allow_None=False, doc=None, label=None, precedence=None, + constant=False, readonly=False, pickle_default_value=True, per_instance=True, + allow_refs=False, nested_refs=False + ): + ... + +
[docs] @_deprecate_positional_args + def __init__(self, default=Undefined, *, class_=Undefined, item_type=Undefined, + instantiate=Undefined, bounds=Undefined, **params): + if class_ is not Undefined: + # PARAM3_DEPRECATION + warnings.warn( + message="The 'class_' attribute on 'List' is deprecated. Use instead 'item_type'", + category=_ParamDeprecationWarning, + stacklevel=3, + ) + if item_type is not Undefined and class_ is not Undefined: + self.item_type = item_type + elif item_type is Undefined or item_type is None: + self.item_type = class_ + else: + self.item_type = item_type + self.class_ = self.item_type + self.bounds = bounds + Parameter.__init__(self, default=default, instantiate=instantiate, + **params) + self._validate(self.default)
+ + def _validate(self, val): + """ + Checks that the value is numeric and that it is within the hard + bounds; if not, an exception is raised. + """ + self._validate_value(val, self.allow_None) + self._validate_bounds(val, self.bounds) + self._validate_item_type(val, self.item_type) + + def _validate_bounds(self, val, bounds): + "Checks that the list is of the right length and has the right contents." + if bounds is None or (val is None and self.allow_None): + return + min_length, max_length = bounds + l = len(val) + if min_length is not None and max_length is not None: + if not (min_length <= l <= max_length): + raise ValueError( + f"{_validate_error_prefix(self)} length must be between " + f"{min_length} and {max_length} (inclusive), not {l}." + ) + elif min_length is not None: + if not min_length <= l: + raise ValueError( + f"{_validate_error_prefix(self)} length must be at " + f"least {min_length}, not {l}." + ) + elif max_length is not None: + if not l <= max_length: + raise ValueError( + f"{_validate_error_prefix(self)} length must be at " + f"most {max_length}, not {l}." + ) + + def _validate_value(self, val, allow_None): + if allow_None and val is None: + return + if not isinstance(val, list): + raise ValueError( + f"{_validate_error_prefix(self)} must be a list, not an " + f"object of {type(val)}." + ) + + def _validate_item_type(self, val, item_type): + if item_type is None or (self.allow_None and val is None): + return + for v in val: + if isinstance(v, item_type): + continue + raise TypeError( + f"{_validate_error_prefix(self)} items must be instances " + f"of {item_type!r}, not {type(v)}." + )
+ + +
[docs]class HookList(List): + """ + Parameter whose value is a list of callable objects. + + This type of List Parameter is typically used to provide a place + for users to register a set of commands to be called at a + specified place in some sequence of processing steps. + """ + __slots__ = ['class_', 'bounds'] + + def _validate_value(self, val, allow_None): + super()._validate_value(val, allow_None) + if allow_None and val is None: + return + for v in val: + if callable(v): + continue + raise ValueError( + f"{_validate_error_prefix(self)} items must be callable, " + f"not {v!r}." + )
+ + +
[docs]class Dict(ClassSelector): + """ + Parameter whose value is a dictionary. + """ + + @typing.overload + def __init__( + self, + default=None, *, is_instance=True, + allow_None=False, doc=None, label=None, precedence=None, instantiate=True, + constant=False, readonly=False, pickle_default_value=True, per_instance=True, + allow_refs=False, nested_refs=False + ): + ... + +
[docs] def __init__(self, default=Undefined, **params): + super().__init__(default=default, class_=dict, **params)
+ + +
[docs]class Array(ClassSelector): + """ + Parameter whose value is a numpy array. + """ + + @typing.overload + def __init__( + self, + default=None, *, is_instance=True, + allow_None=False, doc=None, label=None, precedence=None, instantiate=True, + constant=False, readonly=False, pickle_default_value=True, per_instance=True, + allow_refs=False, nested_refs=False + ): + ... + +
[docs] def __init__(self, default=Undefined, **params): + from numpy import ndarray + super().__init__(default=default, class_=ndarray, **params)
+ + @classmethod + def serialize(cls, value): + if value is None: + return None + return value.tolist() + + @classmethod + def deserialize(cls, value): + if value == 'null' or value is None: + return None + import numpy + if isinstance(value, str): + return _deserialize_from_path( + {'.npy': numpy.load, '.txt': lambda x: numpy.loadtxt(str(x))}, + value, 'Array' + ) + else: + return numpy.asarray(value)
+ + +
[docs]class DataFrame(ClassSelector): + """ + Parameter whose value is a pandas DataFrame. + + The structure of the DataFrame can be constrained by the rows and + columns arguments: + + rows: If specified, may be a number or an integer bounds tuple to + constrain the allowable number of rows. + + columns: If specified, may be a number, an integer bounds tuple, a + list or a set. If the argument is numeric, constrains the number of + columns using the same semantics as used for rows. If either a list + or set of strings, the column names will be validated. If a set is + used, the supplied DataFrame must contain the specified columns and + if a list is given, the supplied DataFrame must contain exactly the + same columns and in the same order and no other columns. + """ + + __slots__ = ['rows', 'columns', 'ordered'] + + _slot_defaults = _dict_update( + ClassSelector._slot_defaults, rows=None, columns=None, ordered=None + ) + + @typing.overload + def __init__( + self, + default=None, *, rows=None, columns=None, ordered=None, is_instance=True, + allow_None=False, doc=None, label=None, precedence=None, instantiate=True, + constant=False, readonly=False, pickle_default_value=True, per_instance=True, + allow_refs=False, nested_refs=False + ): + ... + +
[docs] @_deprecate_positional_args + def __init__(self, default=Undefined, *, rows=Undefined, columns=Undefined, ordered=Undefined, **params): + from pandas import DataFrame as pdDFrame + self.rows = rows + self.columns = columns + self.ordered = ordered + super().__init__(default=default, class_=pdDFrame, **params) + self._validate(self.default)
+ + def _length_bounds_check(self, bounds, length, name): + message = f'{name} length {length} does not match declared bounds of {bounds}' + if not isinstance(bounds, tuple): + if (bounds != length): + raise ValueError(f"{_validate_error_prefix(self)}: {message}") + else: + return + (lower, upper) = bounds + failure = ((lower is not None and (length < lower)) + or (upper is not None and length > upper)) + if failure: + raise ValueError(f"{_validate_error_prefix(self)}: {message}") + + def _validate(self, val): + super()._validate(val) + + if isinstance(self.columns, set) and self.ordered is True: + raise ValueError( + f'{_validate_error_prefix(self)}: columns cannot be ordered ' + f'when specified as a set' + ) + + if self.allow_None and val is None: + return + + if self.columns is None: + pass + elif (isinstance(self.columns, tuple) and len(self.columns)==2 + and all(isinstance(v, (type(None), numbers.Number)) for v in self.columns)): # Numeric bounds tuple + self._length_bounds_check(self.columns, len(val.columns), 'columns') + elif isinstance(self.columns, (list, set)): + self.ordered = isinstance(self.columns, list) if self.ordered is None else self.ordered + difference = set(self.columns) - {str(el) for el in val.columns} + if difference: + raise ValueError( + f"{_validate_error_prefix(self)}: provided columns " + f"{list(val.columns)} does not contain required " + f"columns {sorted(self.columns)}" + ) + else: + self._length_bounds_check(self.columns, len(val.columns), 'column') + + if self.ordered: + if list(val.columns) != list(self.columns): + raise ValueError( + f"{_validate_error_prefix(self)}: provided columns " + f"{list(val.columns)} must exactly match {self.columns}" + ) + if self.rows is not None: + self._length_bounds_check(self.rows, len(val), 'row') + + @classmethod + def serialize(cls, value): + if value is None: + return None + return value.to_dict('records') + + @classmethod + def deserialize(cls, value): + if value == 'null' or value is None: + return None + import pandas + if isinstance(value, str): + return _deserialize_from_path( + { + '.csv': pandas.read_csv, + '.dta': pandas.read_stata, + '.feather': pandas.read_feather, + '.h5': pandas.read_hdf, + '.hdf5': pandas.read_hdf, + '.json': pandas.read_json, + '.ods': pandas.read_excel, + '.parquet': pandas.read_parquet, + '.pkl': pandas.read_pickle, + '.tsv': lambda x: pandas.read_csv(x, sep='\t'), + '.xlsm': pandas.read_excel, + '.xlsx': pandas.read_excel, + }, value, 'DataFrame') + else: + return pandas.DataFrame(value)
+ + +
[docs]class Series(ClassSelector): + """ + Parameter whose value is a pandas Series. + + The structure of the Series can be constrained by the rows argument + which may be a number or an integer bounds tuple to constrain the + allowable number of rows. + """ + + __slots__ = ['rows'] + + _slot_defaults = _dict_update( + ClassSelector._slot_defaults, rows=None, allow_None=False + ) + + @typing.overload + def __init__( + self, + default=None, *, rows=None, allow_None=False, is_instance=True, + doc=None, label=None, precedence=None, instantiate=True, + constant=False, readonly=False, pickle_default_value=True, per_instance=True, + allow_refs=False, nested_refs=False + ): + ... + +
[docs] @_deprecate_positional_args + def __init__(self, default=Undefined, *, rows=Undefined, allow_None=Undefined, **params): + from pandas import Series as pdSeries + self.rows = rows + super().__init__(default=default, class_=pdSeries, allow_None=allow_None, + **params) + self._validate(self.default)
+ + def _length_bounds_check(self, bounds, length, name): + message = f'{name} length {length} does not match declared bounds of {bounds}' + if not isinstance(bounds, tuple): + if (bounds != length): + raise ValueError(f"{_validate_error_prefix(self)}: {message}") + else: + return + (lower, upper) = bounds + failure = ((lower is not None and (length < lower)) + or (upper is not None and length > upper)) + if failure: + raise ValueError(f"{_validate_error_prefix(self)}: {message}") + + def _validate(self, val): + super()._validate(val) + + if self.allow_None and val is None: + return + + if self.rows is not None: + self._length_bounds_check(self.rows, len(val), 'row')
+ + + +# For portable code: +# - specify paths in unix (rather than Windows) style; +# - use resolve_path(path_to_file=True) for paths to existing files to be read, +# - use resolve_path(path_to_file=False) for paths to existing folders to be read, +# and normalize_path() for paths to new files to be written. + +class resolve_path(ParameterizedFunction): + """ + Find the path to an existing file, searching the paths specified + in the search_paths parameter if the filename is not absolute, and + converting a UNIX-style path to the current OS's format if + necessary. + + To turn a supplied relative path into an absolute one, the path is + appended to paths in the search_paths parameter, in order, until + the file is found. + + An IOError is raised if the file is not found. + + Similar to Python's os.path.abspath(), except more search paths + than just os.getcwd() can be used, and the file must exist. + """ + + search_paths = List(default=[os.getcwd()], pickle_default_value=False, doc=""" + Prepended to a non-relative path, in order, until a file is + found.""") + + path_to_file = Boolean(default=True, pickle_default_value=False, + allow_None=True, doc=""" + String specifying whether the path refers to a 'File' or a + 'Folder'. If None, the path may point to *either* a 'File' *or* + a 'Folder'.""") + + def __call__(self, path, **params): + p = ParamOverrides(self, params) + path = os.path.normpath(path) + ftype = "File" if p.path_to_file is True \ + else "Folder" if p.path_to_file is False else "Path" + + if not p.search_paths: + p.search_paths = [os.getcwd()] + + if os.path.isabs(path): + if ((p.path_to_file is None and os.path.exists(path)) or + (p.path_to_file is True and os.path.isfile(path)) or + (p.path_to_file is False and os.path.isdir( path))): + return path + raise OSError(f"{ftype} '{path}' not found.") + + else: + paths_tried = [] + for prefix in p.search_paths: + try_path = os.path.join(os.path.normpath(prefix), path) + + if ((p.path_to_file is None and os.path.exists(try_path)) or + (p.path_to_file is True and os.path.isfile(try_path)) or + (p.path_to_file is False and os.path.isdir( try_path))): + return try_path + + paths_tried.append(try_path) + + raise OSError(ftype + " " + os.path.split(path)[1] + " was not found in the following place(s): " + str(paths_tried) + ".") + + +# PARAM3_DEPRECATION +@_deprecated() +class normalize_path(ParameterizedFunction): + """ + Convert a UNIX-style path to the current OS's format, + typically for creating a new file or directory. + + If the path is not already absolute, it will be made absolute + (using the prefix parameter). + + Should do the same as Python's os.path.abspath(), except using + prefix rather than os.getcwd). + """ + + prefix = String(default=os.getcwd(),pickle_default_value=False,doc=""" + Prepended to the specified path, if that path is not + absolute.""") + + def __call__(self,path="",**params): + p = ParamOverrides(self,params) + + if not os.path.isabs(path): + path = os.path.join(os.path.normpath(p.prefix),path) + + return os.path.normpath(path) + + + +
[docs]class Path(Parameter): + """Parameter that can be set to a string specifying the path of a file or folder. + + The string should be specified in UNIX style, but it will be + returned in the format of the user's operating system. Please use + the Filename or Foldername Parameters if you require discrimination + between the two possibilities. + + The specified path can be absolute, or relative to either: + + * any of the paths specified in the search_paths attribute (if + search_paths is not None); + + or + + * any of the paths searched by resolve_path() (if search_paths + is None). + + Parameters + ---------- + search_paths : list, default=[os.getcwd()] + List of paths to search the path from + check_exists: boolean, default=True + If True (default) the path must exist on instantiation and set, + otherwise the path can optionally exist. + """ + + __slots__ = ['search_paths', 'check_exists'] + + _slot_defaults = _dict_update( + Parameter._slot_defaults, check_exists=True, + ) + + @typing.overload + def __init__( + self, + default=None, *, search_paths=None, check_exists=True, + allow_None=False, doc=None, label=None, precedence=None, instantiate=False, + constant=False, readonly=False, pickle_default_value=True, per_instance=True, + allow_refs=False, nested_refs=False + ): + ... + +
[docs] @_deprecate_positional_args + def __init__(self, default=Undefined, *, search_paths=Undefined, check_exists=Undefined, **params): + if search_paths is Undefined: + search_paths = [] + + self.search_paths = search_paths + if check_exists is not Undefined and not isinstance(check_exists, bool): + raise ValueError("'check_exists' attribute value must be a boolean") + self.check_exists = check_exists + super().__init__(default,**params) + self._validate(self.default)
+ + def _resolve(self, path): + return resolve_path(path, path_to_file=None, search_paths=self.search_paths) + + def _validate(self, val): + if val is None: + if not self.allow_None: + raise ValueError(f'{_validate_error_prefix(self)} does not accept None') + else: + if not isinstance(val, (str, pathlib.Path)): + raise ValueError(f'{_validate_error_prefix(self)} only take str or pathlib.Path types') + try: + self._resolve(val) + except OSError as e: + if self.check_exists: + raise OSError(e.args[0]) from None + + def __get__(self, obj, objtype): + """ + Return an absolute, normalized path (see resolve_path). + """ + raw_path = super().__get__(obj,objtype) + if raw_path is None: + path = None + else: + try: + path = self._resolve(raw_path) + except OSError: + if self.check_exists: + raise + else: + path = raw_path + return path + + def __getstate__(self): + # don't want to pickle the search_paths + state = super().__getstate__() + + if 'search_paths' in state: + state['search_paths'] = [] + + return state
+ + + +
[docs]class Filename(Path): + """ + Parameter that can be set to a string specifying the path of a file. + + The string should be specified in UNIX style, but it will be + returned in the format of the user's operating system. + + The specified path can be absolute, or relative to either: + + * any of the paths specified in the search_paths attribute (if + search_paths is not None); + + or + + * any of the paths searched by resolve_path() (if search_paths + is None). + """ + + def _resolve(self, path): + return resolve_path(path, path_to_file=True, search_paths=self.search_paths)
+ + +
[docs]class Foldername(Path): + """ + Parameter that can be set to a string specifying the path of a folder. + + The string should be specified in UNIX style, but it will be + returned in the format of the user's operating system. + + The specified path can be absolute, or relative to either: + + * any of the paths specified in the search_paths attribute (if + search_paths is not None); + + or + + * any of the paths searched by resolve_dir_path() (if search_paths + is None). + """ + + def _resolve(self, path): + return resolve_path(path, path_to_file=False, search_paths=self.search_paths)
+ + + +def _abbreviate_paths(pathspec,named_paths): + """ + Given a dict of (pathname,path) pairs, removes any prefix shared by all pathnames. + Helps keep menu items short yet unambiguous. + """ + from os.path import commonprefix, dirname, sep + + prefix = commonprefix([dirname(name)+sep for name in named_paths.keys()]+[pathspec]) + return OrderedDict([(name[len(prefix):],path) for name,path in named_paths.items()]) + + +# PARAM3_DEPRECATION +@_deprecated() +def abbreviate_paths(pathspec,named_paths): + """ + Given a dict of (pathname,path) pairs, removes any prefix shared by all pathnames. + Helps keep menu items short yet unambiguous. + + .. deprecated:: 2.0.0 + """ + return _abbreviate_paths(pathspec, named_paths) + + +
[docs]class FileSelector(Selector): + """ + Given a path glob, allows one file to be selected from those matching. + """ + __slots__ = ['path'] + + _slot_defaults = _dict_update( + Selector._slot_defaults, path="", + ) + + @typing.overload + def __init__( + self, + default=None, *, path="", objects=[], instantiate=False, compute_default_fn=None, + check_on_set=None, allow_None=None, empty_default=False, + doc=None, label=None, precedence=None, constant=False, readonly=False, + pickle_default_value=True, per_instance=True, allow_refs=False, nested_refs=False + ): + ... + +
[docs] @_deprecate_positional_args + def __init__(self, default=Undefined, *, path=Undefined, **kwargs): + self.default = default + self.path = path + self.update(path=path) + if default is not Undefined: + self.default = default + super().__init__(default=self.default, objects=self._objects, **kwargs)
+ + def _on_set(self, attribute, old, new): + super()._on_set(attribute, new, old) + if attribute == 'path': + self.update(path=new) + + def update(self, path=Undefined): + if path is Undefined: + path = self.path + if path == "": + self.objects = [] + else: + # Convert using os.fspath and pathlib.Path to handle ensure + # the path separators are consistent (on Windows in particular) + pathpattern = os.fspath(pathlib.Path(path)) + self.objects = sorted(glob.glob(pathpattern)) + if self.default in self.objects: + return + self.default = self.objects[0] if self.objects else None + + def get_range(self): + return _abbreviate_paths(self.path,super().get_range())
+ + +
[docs]class ListSelector(Selector): + """ + Variant of Selector where the value can be multiple objects from + a list of possible objects. + """ + + @typing.overload + def __init__( + self, + default=None, *, objects=[], instantiate=False, compute_default_fn=None, + check_on_set=None, allow_None=None, empty_default=False, + doc=None, label=None, precedence=None, constant=False, readonly=False, + pickle_default_value=True, per_instance=True, allow_refs=False, nested_refs=False + ): + ... + +
[docs] @_deprecate_positional_args + def __init__(self, default=Undefined, *, objects=Undefined, **kwargs): + super().__init__( + objects=objects, default=default, empty_default=True, **kwargs)
+ + def compute_default(self): + if self.default is None and callable(self.compute_default_fn): + self.default = self.compute_default_fn() + for o in self.default: + if o not in self.objects: + self.objects.append(o) + + def _validate(self, val): + self._validate_type(val) + + if self.check_on_set: + self._validate_value(val) + else: + self._ensure_value_is_in_objects(val) + + + def _validate_type(self, val): + if (val is None and self.allow_None): + return + + if not isinstance(val, list): + raise ValueError( + f"{_validate_error_prefix(self)} only takes list types, " + f"not {val!r}." + ) + + def _validate_value(self, val): + self._validate_type(val) + if val is not None: + for o in val: + super()._validate_value(o) + + def _update_state(self): + if self.check_on_set is False and self.default is not None: + for o in self.default: + self._ensure_value_is_in_objects(o)
+ + +
[docs]class MultiFileSelector(ListSelector): + """ + Given a path glob, allows multiple files to be selected from the list of matches. + """ + __slots__ = ['path'] + + _slot_defaults = _dict_update( + Selector._slot_defaults, path="", + ) + + @typing.overload + def __init__( + self, + default=None, *, path="", objects=[], compute_default_fn=None, + check_on_set=None, allow_None=None, empty_default=False, + doc=None, label=None, precedence=None, instantiate=False, + constant=False, readonly=False, pickle_default_value=True, + per_instance=True, allow_refs=False, nested_refs=False + ): + ... + +
[docs] @_deprecate_positional_args + def __init__(self, default=Undefined, *, path=Undefined, **kwargs): + self.default = default + self.path = path + self.update(path=path) + super().__init__(default=default, objects=self._objects, **kwargs)
+ + def _on_set(self, attribute, old, new): + super()._on_set(attribute, new, old) + if attribute == 'path': + self.update(path=new) + + def update(self, path=Undefined): + if path is Undefined: + path = self.path + self.objects = sorted(glob.glob(path)) + if self.default and all([o in self.objects for o in self.default]): + return + elif not self.default: + return + self.default = self.objects + + def get_range(self): + return _abbreviate_paths(self.path,super().get_range())
+ + +def _to_datetime(x): + """ + Internal function that will convert date objs to datetime objs, used + for comparing date and datetime objects without error. + """ + if isinstance(x, dt.date) and not isinstance(x, dt.datetime): + return dt.datetime(*x.timetuple()[:6]) + return x + + +class Date(Number): + """ + Date parameter of datetime or date type. + """ + + _slot_defaults = _dict_update(Number._slot_defaults, default=None) + + @typing.overload + def __init__( + self, + default=None, *, bounds=None, softbounds=None, inclusive_bounds=(True,True), step=None, set_hook=None, + doc=None, label=None, precedence=None, instantiate=False, constant=False, + readonly=False, pickle_default_value=True, allow_None=False, per_instance=True, + allow_refs=False, nested_refs=False + ): + ... + + def __init__(self, default=Undefined, **kwargs): + super().__init__(default=default, **kwargs) + + def _validate_value(self, val, allow_None): + """ + Checks that the value is numeric and that it is within the hard + bounds; if not, an exception is raised. + """ + if self.allow_None and val is None: + return + + if not isinstance(val, dt_types) and not (allow_None and val is None): + raise ValueError( + f"{_validate_error_prefix(self)} only takes datetime and " + f"date types, not {type(val)}." + ) + + def _validate_step(self, val, step): + if step is not None and not isinstance(step, dt_types): + raise ValueError( + f"{_validate_error_prefix(self, 'step')} can only be None, " + f"a datetime or date type, not {type(step)}." + ) + + def _validate_bounds(self, val, bounds, inclusive_bounds): + val = _to_datetime(val) + bounds = None if bounds is None else map(_to_datetime, bounds) + return super()._validate_bounds(val, bounds, inclusive_bounds) + + @classmethod + def serialize(cls, value): + if value is None: + return None + if not isinstance(value, (dt.datetime, dt.date)): # i.e np.datetime64 + value = value.astype(dt.datetime) + return value.strftime("%Y-%m-%dT%H:%M:%S.%f") + + @classmethod + def deserialize(cls, value): + if value == 'null' or value is None: + return None + return dt.datetime.strptime(value, "%Y-%m-%dT%H:%M:%S.%f") + + +class CalendarDate(Number): + """ + Parameter specifically allowing dates (not datetimes). + """ + + _slot_defaults = _dict_update(Number._slot_defaults, default=None) + + @typing.overload + def __init__( + self, + default=None, *, bounds=None, softbounds=None, inclusive_bounds=(True,True), step=None, set_hook=None, + doc=None, label=None, precedence=None, instantiate=False, constant=False, + readonly=False, pickle_default_value=True, allow_None=False, per_instance=True, + allow_refs=False, nested_refs=False + ): + ... + + def __init__(self, default=Undefined, **kwargs): + super().__init__(default=default, **kwargs) + + def _validate_value(self, val, allow_None): + """ + Checks that the value is numeric and that it is within the hard + bounds; if not, an exception is raised. + """ + if self.allow_None and val is None: + return + + if (not isinstance(val, dt.date) or isinstance(val, dt.datetime)) and not (allow_None and val is None): + raise ValueError( + f"{_validate_error_prefix(self)} only takes date types." + ) + + def _validate_step(self, val, step): + if step is not None and not isinstance(step, dt.date): + raise ValueError( + f"{_validate_error_prefix(self, 'step')} can only be None or " + f"a date type, not {type(step)}." + ) + + @classmethod + def serialize(cls, value): + if value is None: + return None + return value.strftime("%Y-%m-%d") + + @classmethod + def deserialize(cls, value): + if value == 'null' or value is None: + return None + return dt.datetime.strptime(value, "%Y-%m-%d").date() + + +
[docs]class Color(Parameter): + """ + Color parameter defined as a hex RGB string with an optional # + prefix or (optionally) as a CSS3 color name. + """ + + # CSS3 color specification https://www.w3.org/TR/css-color-3/#svg-color + _named_colors = [ 'aliceblue', 'antiquewhite', 'aqua', + 'aquamarine', 'azure', 'beige', 'bisque', 'black', + 'blanchedalmond', 'blue', 'blueviolet', 'brown', 'burlywood', + 'cadetblue', 'chartreuse', 'chocolate', 'coral', + 'cornflowerblue', 'cornsilk', 'crimson', 'cyan', 'darkblue', + 'darkcyan', 'darkgoldenrod', 'darkgray', 'darkgrey', + 'darkgreen', 'darkkhaki', 'darkmagenta', 'darkolivegreen', + 'darkorange', 'darkorchid', 'darkred', 'darksalmon', + 'darkseagreen', 'darkslateblue', 'darkslategray', + 'darkslategrey', 'darkturquoise', 'darkviolet', 'deeppink', + 'deepskyblue', 'dimgray', 'dimgrey', 'dodgerblue', + 'firebrick', 'floralwhite', 'forestgreen', 'fuchsia', + 'gainsboro', 'ghostwhite', 'gold', 'goldenrod', 'gray', + 'grey', 'green', 'greenyellow', 'honeydew', 'hotpink', + 'indianred', 'indigo', 'ivory', 'khaki', 'lavender', + 'lavenderblush', 'lawngreen', 'lemonchiffon', 'lightblue', + 'lightcoral', 'lightcyan', 'lightgoldenrodyellow', + 'lightgray', 'lightgrey', 'lightgreen', 'lightpink', + 'lightsalmon', 'lightseagreen', 'lightskyblue', + 'lightslategray', 'lightslategrey', 'lightsteelblue', + 'lightyellow', 'lime', 'limegreen', 'linen', 'magenta', + 'maroon', 'mediumaquamarine', 'mediumblue', 'mediumorchid', + 'mediumpurple', 'mediumseagreen', 'mediumslateblue', + 'mediumspringgreen', 'mediumturquoise', 'mediumvioletred', + 'midnightblue', 'mintcream', 'mistyrose', 'moccasin', + 'navajowhite', 'navy', 'oldlace', 'olive', 'olivedrab', + 'orange', 'orangered', 'orchid', 'palegoldenrod', 'palegreen', + 'paleturquoise', 'palevioletred', 'papayawhip', 'peachpuff', + 'peru', 'pink', 'plum', 'powderblue', 'purple', 'red', + 'rosybrown', 'royalblue', 'saddlebrown', 'salmon', + 'sandybrown', 'seagreen', 'seashell', 'sienna', 'silver', + 'skyblue', 'slateblue', 'slategray', 'slategrey', 'snow', + 'springgreen', 'steelblue', 'tan', 'teal', 'thistle', + 'tomato', 'turquoise', 'violet', 'wheat', 'white', + 'whitesmoke', 'yellow', 'yellowgreen'] + + __slots__ = ['allow_named'] + + _slot_defaults = _dict_update(Parameter._slot_defaults, allow_named=True) + + @typing.overload + def __init__( + self, + default=None, *, allow_named=True, + allow_None=False, doc=None, label=None, precedence=None, instantiate=False, + constant=False, readonly=False, pickle_default_value=True, per_instance=True, + allow_refs=False, nested_refs=False + ): + ... + +
[docs] @_deprecate_positional_args + def __init__(self, default=Undefined, *, allow_named=Undefined, **kwargs): + super().__init__(default=default, **kwargs) + self.allow_named = allow_named + self._validate(self.default)
+ + def _validate(self, val): + self._validate_value(val, self.allow_None) + self._validate_allow_named(val, self.allow_named) + + def _validate_value(self, val, allow_None): + if (allow_None and val is None): + return + if not isinstance(val, str): + raise ValueError( + f"{_validate_error_prefix(self)} expects a string value, " + f"not an object of {type(val)}." + ) + + def _validate_allow_named(self, val, allow_named): + if (val is None and self.allow_None): + return + is_hex = re.match('^#?(([0-9a-fA-F]{2}){3}|([0-9a-fA-F]){3})$', val) + if self.allow_named: + if not is_hex and val.lower() not in self._named_colors: + raise ValueError( + f"{_validate_error_prefix(self)} only takes RGB hex codes " + f"or named colors, received '{val}'." + ) + elif not is_hex: + raise ValueError( + f"{_validate_error_prefix(self)} only accepts valid RGB hex " + f"codes, received {val!r}." + )
+ + +
[docs]class Range(NumericTuple): + """ + A numeric range with optional bounds and softbounds. + """ + + __slots__ = ['bounds', 'inclusive_bounds', 'softbounds', 'step'] + + _slot_defaults = _dict_update( + NumericTuple._slot_defaults, default=None, bounds=None, + inclusive_bounds=(True,True), softbounds=None, step=None + ) + + @typing.overload + def __init__( + self, + default=None, *, bounds=None, softbounds=None, inclusive_bounds=(True,True), step=None, length=None, + doc=None, label=None, precedence=None, instantiate=False, constant=False, + readonly=False, pickle_default_value=True, allow_None=False, per_instance=True, + allow_refs=False, nested_refs=False + ): + ... + +
[docs] @_deprecate_positional_args + def __init__(self, default=Undefined, *, bounds=Undefined, softbounds=Undefined, + inclusive_bounds=Undefined, step=Undefined, **params): + self.bounds = bounds + self.inclusive_bounds = inclusive_bounds + self.softbounds = softbounds + self.step = step + super().__init__(default=default,length=2,**params)
+ + def _validate(self, val): + super()._validate(val) + self._validate_bounds(val, self.bounds, self.inclusive_bounds, 'bound') + self._validate_bounds(val, self.softbounds, self.inclusive_bounds, 'softbound') + self._validate_step(val, self.step) + self._validate_order(val, self.step, allow_None=self.allow_None) + + def _validate_step(self, val, step): + if step is not None: + if not _is_number(step): + raise ValueError( + f"{_validate_error_prefix(self, 'step')} can only be None " + f"or a numeric value, not {type(step)}." + ) + elif step == 0: + raise ValueError( + f"{_validate_error_prefix(self, 'step')} cannot be 0." + ) + + def _validate_order(self, val, step, allow_None): + if val is None and allow_None: + return + elif val is not None and (val[0] is None or val[1] is None): + return + + start, end = val + if step is not None and step > 0 and not start <= end: + raise ValueError( + f"{_validate_error_prefix(self)} end {end} is less than its " + f"start {start} with positive step {step}." + ) + elif step is not None and step < 0 and not start >= end: + raise ValueError( + f"{_validate_error_prefix(self)} start {start} is less than its " + f"start {end} with negative step {step}." + ) + + def _validate_bound_type(self, value, position, kind): + if not _is_number(value): + raise ValueError( + f"{_validate_error_prefix(self)} {position} {kind} can only be " + f"None or a numerical value, not {type(value)}." + ) + + def _validate_bounds(self, val, bounds, inclusive_bounds, kind): + if bounds is not None: + for pos, v in zip(['lower', 'upper'], bounds): + if v is None: + continue + self._validate_bound_type(v, pos, kind) + if kind == 'softbound': + return + + if bounds is None or (val is None and self.allow_None): + return + vmin, vmax = bounds + incmin, incmax = inclusive_bounds + for bound, v in zip(['lower', 'upper'], val): + too_low = (vmin is not None) and (v < vmin if incmin else v <= vmin) + too_high = (vmax is not None) and (v > vmax if incmax else v >= vmax) + if too_low or too_high: + raise ValueError( + f"{_validate_error_prefix(self)} {bound} bound must be in " + f"range {self.rangestr()}, not {v}." + ) + + def get_soft_bounds(self): + return get_soft_bounds(self.bounds, self.softbounds) + + def rangestr(self): + vmin, vmax = self.bounds + incmin, incmax = self.inclusive_bounds + incmin = '[' if incmin else '(' + incmax = ']' if incmax else ')' + return f'{incmin}{vmin}, {vmax}{incmax}'
+ + +
[docs]class DateRange(Range): + """ + A datetime or date range specified as (start, end). + + Bounds must be specified as datetime or date types (see param.dt_types). + """ + + def _validate_bound_type(self, value, position, kind): + if not isinstance(value, dt_types): + raise ValueError( + f"{_validate_error_prefix(self)} {position} {kind} can only be " + f"None or a date/datetime value, not {type(value)}." + ) + + def _validate_bounds(self, val, bounds, inclusive_bounds, kind): + val = None if val is None else tuple(map(_to_datetime, val)) + bounds = None if bounds is None else tuple(map(_to_datetime, bounds)) + super()._validate_bounds(val, bounds, inclusive_bounds, kind) + + def _validate_value(self, val, allow_None): + # Cannot use super()._validate_value as DateRange inherits from + # NumericTuple which check that the tuple values are numbers and + # datetime objects aren't numbers. + if allow_None and val is None: + return + + if not isinstance(val, tuple): + raise ValueError( + f"{_validate_error_prefix(self)} only takes a tuple value, " + f"not {type(val)}." + ) + for n in val: + if isinstance(n, dt_types): + continue + raise ValueError( + f"{_validate_error_prefix(self)} only takes date/datetime " + f"values, not {type(n)}." + ) + + start, end = val + if not end >= start: + raise ValueError( + f"{_validate_error_prefix(self)} end datetime {val[1]} " + f"is before start datetime {val[0]}." + ) + + @classmethod + def serialize(cls, value): + if value is None: + return None + # List as JSON has no tuple representation + serialized = [] + for v in value: + if not isinstance(v, (dt.datetime, dt.date)): # i.e np.datetime64 + v = v.astype(dt.datetime) + # Separate date and datetime to deserialize to the right type. + if type(v) == dt.date: + v = v.strftime("%Y-%m-%d") + else: + v = v.strftime("%Y-%m-%dT%H:%M:%S.%f") + serialized.append(v) + return serialized + + def deserialize(cls, value): + if value == 'null' or value is None: + return None + deserialized = [] + for v in value: + # Date + if len(v) == 10: + v = dt.datetime.strptime(v, "%Y-%m-%d").date() + # Datetime + else: + v = dt.datetime.strptime(v, "%Y-%m-%dT%H:%M:%S.%f") + deserialized.append(v) + # As JSON has no tuple representation + return tuple(deserialized)
+ +
[docs]class CalendarDateRange(Range): + """ + A date range specified as (start_date, end_date). + """ + def _validate_value(self, val, allow_None): + if allow_None and val is None: + return + + for n in val: + if not isinstance(n, dt.date): + raise ValueError( + f"{_validate_error_prefix(self)} only takes date types, " + f"not {val}." + ) + + start, end = val + if not end >= start: + raise ValueError( + f"{_validate_error_prefix(self)} end date {val[1]} is before " + f"start date {val[0]}." + ) + + def _validate_bound_type(self, value, position, kind): + if not isinstance(value, dt.date): + raise ValueError( + f"{_validate_error_prefix(self)} {position} {kind} can only be " + f"None or a date value, not {type(value)}." + ) + + @classmethod + def serialize(cls, value): + if value is None: + return None + # As JSON has no tuple representation + return [v.strftime("%Y-%m-%d") for v in value] + + @classmethod + def deserialize(cls, value): + if value == 'null' or value is None: + return None + # As JSON has no tuple representation + return tuple([dt.datetime.strptime(v, "%Y-%m-%d").date() for v in value])
+ + +
[docs]class Event(Boolean): + """ + An Event Parameter is one whose value is intimately linked to the + triggering of events for watchers to consume. Event has a Boolean + value, which when set to True triggers the associated watchers (as + any Parameter does) and then is automatically set back to + False. Conversely, if events are triggered directly via `.trigger`, + the value is transiently set to True (so that it's clear which of + many parameters being watched may have changed), then restored to + False when the triggering completes. An Event parameter is thus like + a momentary switch or pushbutton with a transient True value that + serves only to launch some other action (e.g. via a param.depends + decorator), rather than encapsulating the action itself as + param.Action does. + """ + + # _autotrigger_value specifies the value used to set the parameter + # to when the parameter is supplied to the trigger method. This + # value change is then what triggers the watcher callbacks. + __slots__ = ['_autotrigger_value', '_mode', '_autotrigger_reset_value'] + + @typing.overload + def __init__( + self, + default=False, *, + allow_None=False, doc=None, label=None, precedence=None, instantiate=False, + constant=False, readonly=False, pickle_default_value=True, per_instance=True, + allow_refs=False, nested_refs=False + ): + ... + +
[docs] @_deprecate_positional_args + def __init__(self,default=False,**params): + self._autotrigger_value = True + self._autotrigger_reset_value = False + self._mode = 'set-reset' + # Mode can be one of 'set', 'set-reset' or 'reset' + + # 'set' is normal Boolean parameter behavior when set with a value. + # 'set-reset' temporarily sets the parameter (which triggers + # watching callbacks) but immediately resets the value back to + # False. + # 'reset' applies the reset from True to False without + # triggering watched callbacks + + # This _mode attribute is one of the few places where a specific + # parameter has a special behavior that is relied upon by the + # core functionality implemented in + # parameterized.py. Specifically, the set_param method + # temporarily sets this attribute in order to disable resetting + # back to False while triggered callbacks are executing + super().__init__(default=default,**params)
+ + def _reset_event(self, obj, val): + val = False + if obj is None: + self.default = val + else: + obj._param__private.values[self.name] = val + self._post_setter(obj, val) + + @instance_descriptor + def __set__(self, obj, val): + if self._mode in ['set-reset', 'set']: + super().__set__(obj, val) + if self._mode in ['set-reset', 'reset']: + self._reset_event(obj, val)
+ + +@contextmanager +def exceptions_summarized(): + """Useful utility for writing docs that need to show expected errors. + Shows exception only, concisely, without a traceback. + """ + try: + yield + except Exception: + import sys + etype, value, tb = sys.exc_info() + print(f"{etype.__name__}: {value}", file=sys.stderr) + +from .reactive import bind, rx # noqa: api import +
+ +
+ + + +
+ +
+ +
+
+
+ +
+ +
+ +
+ + + + +
+ + +
+
+
+ + + + + + + + \ No newline at end of file diff --git a/_modules/param/depends.html b/_modules/param/depends.html new file mode 100644 index 0000000..15e899d --- /dev/null +++ b/_modules/param/depends.html @@ -0,0 +1,776 @@ + + + + + + + + + + + param.depends — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +

Source code for param.depends

+import weakref
+
+from collections import defaultdict
+from functools import wraps
+
+from .parameterized import (
+    Parameter, Parameterized, ParameterizedMetaclass, transform_reference,
+)
+from ._utils import accept_arguments, iscoroutinefunction
+
+_display_accessors = {}
+_reactive_display_objs = weakref.WeakSet()
+
+def register_display_accessor(name, accessor, force=False):
+    if name in _display_accessors and not force:
+        raise KeyError(
+            'Display accessor {name!r} already registered. Override it '
+            'by setting force=True or unregister the existing accessor first.')
+    _display_accessors[name] = accessor
+    for fn in _reactive_display_objs:
+        setattr(fn, name, accessor(fn))
+
+def unregister_display_accessor(name):
+    if name not in _display_accessors:
+        raise KeyError('No such display accessor: {name!r}')
+    del _display_accessors[name]
+    for fn in _reactive_display_objs:
+        delattr(fn, name)
+
+
+
[docs]@accept_arguments +def depends(func, *dependencies, watch=False, on_init=False, **kw): + """Annotates a function or Parameterized method to express its dependencies. + + The specified dependencies can be either be Parameter instances or if a + method is supplied they can be defined as strings referring to Parameters + of the class, or Parameters of subobjects (Parameterized objects that are + values of this object's parameters). Dependencies can either be on + Parameter values, or on other metadata about the Parameter. + + Parameters + ---------- + watch : bool, optional + Whether to invoke the function/method when the dependency is updated, + by default False + on_init : bool, optional + Whether to invoke the function/method when the instance is created, + by default False + """ + dependencies, kw = ( + tuple(transform_reference(arg) for arg in dependencies), + {key: transform_reference(arg) for key, arg in kw.items()} + ) + + if iscoroutinefunction(func): + @wraps(func) + async def _depends(*args, **kw): + return await func(*args, **kw) + else: + @wraps(func) + def _depends(*args, **kw): + return func(*args, **kw) + + deps = list(dependencies)+list(kw.values()) + string_specs = False + for dep in deps: + if isinstance(dep, str): + string_specs = True + elif hasattr(dep, '_dinfo'): + pass + elif not isinstance(dep, Parameter): + raise ValueError('The depends decorator only accepts string ' + 'types referencing a parameter or parameter ' + 'instances, found %s type instead.' % + type(dep).__name__) + elif not (isinstance(dep.owner, Parameterized) or + (isinstance(dep.owner, ParameterizedMetaclass))): + owner = 'None' if dep.owner is None else '%s class' % type(dep.owner).__name__ + raise ValueError('Parameters supplied to the depends decorator, ' + 'must be bound to a Parameterized class or ' + 'instance, not %s.' % owner) + + if (any(isinstance(dep, Parameter) for dep in deps) and + any(isinstance(dep, str) for dep in deps)): + raise ValueError('Dependencies must either be defined as strings ' + 'referencing parameters on the class defining ' + 'the decorated method or as parameter instances. ' + 'Mixing of string specs and parameter instances ' + 'is not supported.') + elif string_specs and kw: + raise AssertionError('Supplying keywords to the decorated method ' + 'or function is not supported when referencing ' + 'parameters by name.') + + if not string_specs and watch: # string_specs case handled elsewhere (later), in Parameterized.__init__ + if iscoroutinefunction(func): + async def cb(*events): + args = (getattr(dep.owner, dep.name) for dep in dependencies) + dep_kwargs = {n: getattr(dep.owner, dep.name) for n, dep in kw.items()} + await func(*args, **dep_kwargs) + else: + def cb(*events): + args = (getattr(dep.owner, dep.name) for dep in dependencies) + dep_kwargs = {n: getattr(dep.owner, dep.name) for n, dep in kw.items()} + return func(*args, **dep_kwargs) + + grouped = defaultdict(list) + for dep in deps: + grouped[id(dep.owner)].append(dep) + for group in grouped.values(): + group[0].owner.param.watch(cb, [dep.name for dep in group]) + + _dinfo = getattr(func, '_dinfo', {}) + _dinfo.update({'dependencies': dependencies, + 'kw': kw, 'watch': watch, 'on_init': on_init}) + + _depends._dinfo = _dinfo + + return _depends
+
+ +
+ + + +
+ +
+ +
+
+
+ +
+ +
+ +
+ + + + +
+ + +
+
+
+ + + + + + + + \ No newline at end of file diff --git a/_modules/param/parameterized.html b/_modules/param/parameterized.html new file mode 100644 index 0000000..015cb28 --- /dev/null +++ b/_modules/param/parameterized.html @@ -0,0 +1,5162 @@ + + + + + + + + + + + param.parameterized — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +

Source code for param.parameterized

+"""
+Generic support for objects with full-featured Parameters and
+messaging.
+
+This file comes from the Param library (https://github.com/holoviz/param)
+but can be taken out of the param module and used on its own if desired,
+either alone (providing basic Parameter support) or with param's
+__init__.py (providing specialized Parameter types).
+"""
+
+import asyncio
+import copy
+import datetime as dt
+import html
+import inspect
+import logging
+import numbers
+import operator
+import random
+import re
+import types
+import typing
+import warnings
+
+# Allow this file to be used standalone if desired, albeit without JSON serialization
+try:
+    from . import serializer
+except ImportError:
+    serializer = None
+
+from collections import defaultdict, namedtuple, OrderedDict
+from functools import partial, wraps, reduce
+from html import escape
+from itertools import chain
+from operator import itemgetter, attrgetter
+from types import FunctionType, MethodType
+
+from contextlib import contextmanager
+from logging import DEBUG, INFO, WARNING, ERROR, CRITICAL
+
+from ._utils import (
+    DEFAULT_SIGNATURE,
+    ParamDeprecationWarning as _ParamDeprecationWarning,
+    ParamFutureWarning as _ParamFutureWarning,
+    _deprecated,
+    _deprecate_positional_args,
+    _dict_update,
+    _is_auto_name,
+    _is_mutable_container,
+    _recursive_repr,
+    _validate_error_prefix,
+    accept_arguments,
+    iscoroutinefunction
+)
+
+try:
+    get_ipython()
+except NameError:
+    param_pager = None
+else:
+    # In case the optional ipython module is unavailable
+    try:
+        from .ipython import ParamPager
+        param_pager = ParamPager(metaclass=True)  # Generates param description
+    except:
+        param_pager = None
+
+from inspect import getfullargspec
+
+dt_types = (dt.datetime, dt.date)
+_int_types = (int,)
+
+try:
+    import numpy as np
+    dt_types = dt_types + (np.datetime64,)
+    _int_types = _int_types + (np.integer,)
+except:
+    pass
+
+VERBOSE = INFO - 1
+logging.addLevelName(VERBOSE, "VERBOSE")
+
+# Get the appropriate logging.Logger instance. If `logger` is None, a
+# logger named `"param"` will be instantiated. If `name` is set, a descendant
+# logger with the name ``"param.<name>"`` is returned (or
+# ``logger.name + ".<name>"``)
+logger = None
+
[docs]def get_logger(name=None): + if logger is None: + root_logger = logging.getLogger('param') + if not root_logger.handlers: + root_logger.setLevel(logging.INFO) + formatter = logging.Formatter( + fmt='%(levelname)s:%(name)s: %(message)s') + handler = logging.StreamHandler() + handler.setFormatter(formatter) + root_logger.addHandler(handler) + else: + root_logger = logger + if name is None: + return root_logger + else: + return logging.getLogger(root_logger.name + '.' + name)
+ + +# Indicates whether warnings should be raised as errors, stopping +# processing. +warnings_as_exceptions = False + +docstring_signature = True # Add signature to class docstrings +docstring_describe_params = True # Add parameter description to class + # docstrings (requires ipython module) +object_count = 0 +warning_count = 0 + +# Hook to apply to depends and bind arguments to turn them into valid parameters +_reference_transforms = [] + +def register_reference_transform(transform): + """ + Appends a transform to extract potential parameter dependencies + from an object. + + Arguments + --------- + transform: Callable[Any, Any] + """ + return _reference_transforms.append(transform) + +def transform_reference(arg): + """ + Applies transforms to turn objects which should be treated like + a parameter reference into a valid reference that can be resolved + by Param. This is useful for adding handling for depending on objects + that are not simple Parameters or functions with dependency + definitions. + """ + for transform in _reference_transforms: + if isinstance(arg, Parameter) or hasattr(arg, '_dinfo'): + break + arg = transform(arg) + return arg + +def eval_function_with_deps(function): + """Evaluates a function after resolving its dependencies. + + Calls and returns a function after resolving any dependencies + stored on the _dinfo attribute and passing the resolved values + as arguments. + """ + args, kwargs = (), {} + if hasattr(function, '_dinfo'): + arg_deps = function._dinfo['dependencies'] + kw_deps = function._dinfo.get('kw', {}) + if kw_deps or any(isinstance(d, Parameter) for d in arg_deps): + args = (getattr(dep.owner, dep.name) for dep in arg_deps) + kwargs = {n: getattr(dep.owner, dep.name) for n, dep in kw_deps.items()} + return function(*args, **kwargs) + +def resolve_value(value): + """ + Resolves the current value of a dynamic reference. + """ + if isinstance(value, (list, tuple)): + return type(value)(resolve_value(v) for v in value) + elif isinstance(value, dict): + return type(value)((resolve_value(k), resolve_value(v)) for k, v in value.items()) + elif isinstance(value, slice): + return slice( + resolve_value(value.start), + resolve_value(value.stop), + resolve_value(value.step) + ) + value = transform_reference(value) + if hasattr(value, '_dinfo'): + value = eval_function_with_deps(value) + elif isinstance(value, Parameter): + value = getattr(value.owner, value.name) + return value + +def resolve_ref(reference, recursive=False): + """ + Resolves all parameters a dynamic reference depends on. + """ + if recursive: + if isinstance(reference, (list, tuple, set)): + return [r for v in reference for r in resolve_ref(v)] + elif isinstance(reference, dict): + return [r for kv in reference.items() for o in kv for r in resolve_ref(o)] + elif isinstance(reference, slice): + return [r for v in (reference.start, reference.stop, reference.step) for r in resolve_ref(v)] + reference = transform_reference(reference) + if hasattr(reference, '_dinfo'): + dinfo = getattr(reference, '_dinfo', {}) + args = list(dinfo.get('dependencies', [])) + kwargs = list(dinfo.get('kw', {}).values()) + refs = [] + for arg in (args + kwargs): + if isinstance(arg, str): + owner = get_method_owner(reference) + if arg in owner.param: + arg = owner.param[arg] + elif '.' in arg: + path = arg.split('.') + arg = owner + for attr in path[:-1]: + arg = getattr(arg, attr) + arg = arg.param[path[-1]] + else: + arg = getattr(owner, arg) + refs.extend(resolve_ref(arg)) + return refs + elif isinstance(reference, Parameter): + return [reference] + return [] + +def _identity_hook(obj, val): + """To be removed when set_hook is removed""" + return val + + +class _Undefined: + """ + Dummy value to signal completely undefined values rather than + simple None values. + """ + + def __bool__(self): + # Haven't defined whether Undefined is falsy or truthy, + # so to avoid subtle bugs raise an error when it + # is used in a comparison without `is`. + raise RuntimeError('Use `is` to compare Undefined') + + def __repr__(self): + return '<Undefined>' + + +Undefined = _Undefined() + + +
[docs]@contextmanager +def logging_level(level): + """ + Temporarily modify param's logging level. + """ + level = level.upper() + levels = [DEBUG, INFO, WARNING, ERROR, CRITICAL, VERBOSE] + level_names = ['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL', 'VERBOSE'] + + if level not in level_names: + raise Exception(f"Level {level!r} not in {levels!r}") + + param_logger = get_logger() + logging_level = param_logger.getEffectiveLevel() + param_logger.setLevel(levels[level_names.index(level)]) + try: + yield None + finally: + param_logger.setLevel(logging_level)
+ + +@contextmanager +def _batch_call_watchers(parameterized, enable=True, run=True): + """ + Internal version of batch_call_watchers, adding control over queueing and running. + Only actually batches events if enable=True; otherwise a no-op. Only actually + calls the accumulated watchers on exit if run=True; otherwise they remain queued. + """ + BATCH_WATCH = parameterized.param._BATCH_WATCH + parameterized.param._BATCH_WATCH = enable or parameterized.param._BATCH_WATCH + try: + yield + finally: + parameterized.param._BATCH_WATCH = BATCH_WATCH + if run and not BATCH_WATCH: + parameterized.param._batch_call_watchers() + + +# PARAM3_DEPRECATION +
[docs]@_deprecated(extra_msg="Use instead `batch_call_watchers`.") +@contextmanager +def batch_watch(parameterized, enable=True, run=True): + with _batch_call_watchers(parameterized, enable, run): + yield
+ + +
[docs]@contextmanager +def batch_call_watchers(parameterized): + """ + Context manager to batch events to provide to Watchers on a + parameterized object. This context manager queues any events + triggered by setting a parameter on the supplied parameterized + object, saving them up to dispatch them all at once when the + context manager exits. + """ + BATCH_WATCH = parameterized.param._BATCH_WATCH + parameterized.param._BATCH_WATCH = True + try: + yield + finally: + parameterized.param._BATCH_WATCH = BATCH_WATCH + if not BATCH_WATCH: + parameterized.param._batch_call_watchers()
+ + +@contextmanager +def _syncing(parameterized, parameters): + old = parameterized._param__private.syncing + parameterized._param__private.syncing = set(old) | set(parameters) + try: + yield + finally: + parameterized._param__private.syncing = old + + +
[docs]@contextmanager +def edit_constant(parameterized): + """ + Temporarily set parameters on Parameterized object to constant=False + to allow editing them. + """ + params = parameterized.param.objects('existing').values() + constants = [p.constant for p in params] + for p in params: + p.constant = False + try: + yield + except: + raise + finally: + for (p, const) in zip(params, constants): + p.constant = const
+ + +
[docs]@contextmanager +def discard_events(parameterized): + """ + Context manager that discards any events within its scope + triggered on the supplied parameterized object. + """ + batch_watch = parameterized.param._BATCH_WATCH + parameterized.param._BATCH_WATCH = True + watchers, events = (list(parameterized.param._state_watchers), + list(parameterized.param._events)) + try: + yield + except: + raise + finally: + parameterized.param._BATCH_WATCH = batch_watch + parameterized.param._state_watchers = watchers + parameterized.param._events = events
+ + +# External components can register an async executor which will run +# async functions +async_executor = None + + +def classlist(class_): + """ + Return a list of the class hierarchy above (and including) the given class. + + Same as `inspect.getmro(class_)[::-1]` + """ + return inspect.getmro(class_)[::-1] + + +def descendents(class_): + """ + Return a list of the class hierarchy below (and including) the given class. + + The list is ordered from least- to most-specific. Can be useful for + printing the contents of an entire class hierarchy. + """ + assert isinstance(class_,type) + q = [class_] + out = [] + while len(q): + x = q.pop(0) + out.insert(0,x) + for b in x.__subclasses__(): + if b not in q and b not in out: + q.append(b) + return out[::-1] + + +def get_all_slots(class_): + """ + Return a list of slot names for slots defined in `class_` and its + superclasses. + """ + # A subclass's __slots__ attribute does not contain slots defined + # in its superclass (the superclass' __slots__ end up as + # attributes of the subclass). + all_slots = [] + parent_param_classes = [c for c in classlist(class_)[1::]] + for c in parent_param_classes: + if hasattr(c,'__slots__'): + all_slots+=c.__slots__ + return all_slots + + +def get_occupied_slots(instance): + """ + Return a list of slots for which values have been set. + + (While a slot might be defined, if a value for that slot hasn't + been set, then it's an AttributeError to request the slot's + value.) + """ + return [slot for slot in get_all_slots(type(instance)) + if hasattr(instance,slot)] + + +# PARAM3_DEPRECATION +@_deprecated() +def all_equal(arg1,arg2): + """ + Return a single boolean for arg1==arg2, even for numpy arrays + using element-wise comparison. + + Uses all(arg1==arg2) for sequences, and arg1==arg2 otherwise. + + If both objects have an '_infinitely_iterable' attribute, they are + not be zipped together and are compared directly instead. + """ + if all(hasattr(el, '_infinitely_iterable') for el in [arg1,arg2]): + return arg1==arg2 + try: + return all(a1 == a2 for a1, a2 in zip(arg1, arg2)) + except TypeError: + return arg1==arg2 + + +# PARAM3_DEPRECATION +# The syntax to use a metaclass changed incompatibly between 2 and +# 3. The add_metaclass() class decorator below creates a class using a +# specified metaclass in a way that works on both 2 and 3. For 3, can +# remove this decorator and specify metaclasses in a simpler way +# (https://docs.python.org/3/reference/datamodel.html#customizing-class-creation) +# +# Code from six (https://bitbucket.org/gutworth/six; version 1.4.1). +@_deprecated() +def add_metaclass(metaclass): + """Class decorator for creating a class with a metaclass. + + .. deprecated:: 2.0.0 + """ + def wrapper(cls): + orig_vars = cls.__dict__.copy() + orig_vars.pop('__dict__', None) + orig_vars.pop('__weakref__', None) + for slots_var in orig_vars.get('__slots__', ()): + orig_vars.pop(slots_var) + return metaclass(cls.__name__, cls.__bases__, orig_vars) + return wrapper + + +class bothmethod: + """ + 'optional @classmethod' + + A decorator that allows a method to receive either the class + object (if called on the class) or the instance object + (if called on the instance) as its first argument. + """ + def __init__(self, method): + self.method = method + + def __get__(self, instance, owner): + if instance is None: + # Class call + return self.method.__get__(owner) + else: + # Instance call + return self.method.__get__(instance, owner) + + +def _getattrr(obj, attr, *args): + def _getattr(obj, attr): + return getattr(obj, attr, *args) + return reduce(_getattr, [obj] + attr.split('.')) + + +def no_instance_params(cls): + """ + Disables instance parameters on the class + """ + cls._param__private.disable_instance_params = True + return cls + + +def _instantiate_param_obj(paramobj, owner=None): + """Return a Parameter object suitable for instantiation given the class's Parameter object""" + + # Shallow-copy Parameter object without the watchers + p = copy.copy(paramobj) + p.owner = owner + + # Reset watchers since class parameter watcher should not execute + # on instance parameters + p.watchers = {} + + # shallow-copy any mutable slot values other than the actual default + for s in p.__class__.__slots__: + v = getattr(p, s) + if _is_mutable_container(v) and s != "default": + setattr(p, s, copy.copy(v)) + return p + + +def _instantiated_parameter(parameterized, param): + """ + Given a Parameterized object and one of its class Parameter objects, + return the appropriate Parameter object for this instance, instantiating + it if need be. + """ + if (getattr(parameterized._param__private, 'initialized', False) and param.per_instance and + not getattr(type(parameterized)._param__private, 'disable_instance_params', False)): + key = param.name + + if key not in parameterized._param__private.params: + parameterized._param__private.params[key] = _instantiate_param_obj(param, parameterized) + + param = parameterized._param__private.params[key] + + return param + + +def instance_descriptor(f): + # If parameter has an instance Parameter, delegate setting + def _f(self, obj, val): + # obj is None when the metaclass is setting + if obj is not None: + instance_param = obj._param__private.params.get(self.name) + if instance_param is None: + instance_param = _instantiated_parameter(obj, self) + if instance_param is not None and self is not instance_param: + instance_param.__set__(obj, val) + return + return f(self, obj, val) + return _f + + +def get_method_owner(method): + """ + Gets the instance that owns the supplied method + """ + if not inspect.ismethod(method): + return None + if isinstance(method, partial): + method = method.func + return method.__self__ + + +# PARAM3_DEPRECATION +def recursive_repr(fillvalue='...'): + """ + Decorator to make a repr function return fillvalue for a recursive call + + .. deprecated:: 1.12.0 + """ + warnings.warn( + 'recursive_repr has been deprecated and will be removed in a future version.', + category=_ParamDeprecationWarning, + stacklevel=2, + ) + return _recursive_repr(fillvalue=fillvalue) + + +
[docs]@accept_arguments +def output(func, *output, **kw): + """ + output allows annotating a method on a Parameterized class to + declare that it returns an output of a specific type. The outputs + of a Parameterized class can be queried using the + Parameterized.param.outputs method. By default the output will + inherit the method name but a custom name can be declared by + expressing the Parameter type using a keyword argument. + + The simplest declaration simply declares the method returns an + object without any type guarantees, e.g.: + + @output() + + If a specific parameter type is specified this is a declaration + that the method will return a value of that type, e.g.: + + @output(param.Number()) + + To override the default name of the output the type may be declared + as a keyword argument, e.g.: + + @output(custom_name=param.Number()) + + Multiple outputs may be declared using keywords mapping from output name + to the type or using tuples of the same format, i.e. these two declarations + are equivalent: + + @output(number=param.Number(), string=param.String()) + + @output(('number', param.Number()), ('string', param.String())) + + output also accepts Python object types which will be upgraded to + a ClassSelector, e.g.: + + @output(int) + """ + if output: + outputs = [] + for i, out in enumerate(output): + i = i if len(output) > 1 else None + if isinstance(out, tuple) and len(out) == 2 and isinstance(out[0], str): + outputs.append(out+(i,)) + elif isinstance(out, str): + outputs.append((out, Parameter(), i)) + else: + outputs.append((None, out, i)) + elif kw: + # (requires keywords to be kept ordered, which was not true in previous versions) + outputs = [(name, otype, i if len(kw) > 1 else None) + for i, (name, otype) in enumerate(kw.items())] + else: + outputs = [(None, Parameter(), None)] + + names, processed = [], [] + for name, otype, i in outputs: + if isinstance(otype, type): + if issubclass(otype, Parameter): + otype = otype() + else: + from .import ClassSelector + otype = ClassSelector(class_=otype) + elif isinstance(otype, tuple) and all(isinstance(t, type) for t in otype): + from .import ClassSelector + otype = ClassSelector(class_=otype) + if not isinstance(otype, Parameter): + raise ValueError('output type must be declared with a Parameter class, ' + 'instance or a Python object type.') + processed.append((name, otype, i)) + names.append(name) + + if len(set(names)) != len(names): + raise ValueError('When declaring multiple outputs each value ' + 'must be unique.') + + _dinfo = getattr(func, '_dinfo', {}) + _dinfo.update({'outputs': processed}) + + @wraps(func) + def _output(*args,**kw): + return func(*args,**kw) + + _output._dinfo = _dinfo + + return _output
+ + +def _parse_dependency_spec(spec): + """ + Parses param.depends specifications into three components: + + 1. The dotted path to the sub-object + 2. The attribute being depended on, i.e. either a parameter or method + 3. The parameter attribute being depended on + """ + assert spec.count(":")<=1 + spec = spec.strip() + m = re.match("(?P<path>[^:]*):?(?P<what>.*)", spec) + what = m.group('what') + path = "."+m.group('path') + m = re.match(r"(?P<obj>.*)(\.)(?P<attr>.*)", path) + obj = m.group('obj') + attr = m.group("attr") + return obj or None, attr, what or 'value' + + +def _params_depended_on(minfo, dynamic=True, intermediate=True): + """ + Resolves dependencies declared on a Parameterized method. + Dynamic dependencies, i.e. dependencies on sub-objects which may + or may not yet be available, are only resolved if dynamic=True. + By default intermediate dependencies, i.e. dependencies on the + path to a sub-object are returned. For example for a dependency + on 'a.b.c' dependencies on 'a' and 'b' are returned as long as + intermediate=True. + + Returns lists of concrete dependencies on available parameters + and dynamic dependencies specifications which have to resolved + if the referenced sub-objects are defined. + """ + deps, dynamic_deps = [], [] + dinfo = getattr(minfo.method, "_dinfo", {}) + for d in dinfo.get('dependencies', list(minfo.cls.param)): + ddeps, ddynamic_deps = (minfo.cls if minfo.inst is None else minfo.inst).param._spec_to_obj(d, dynamic, intermediate) + dynamic_deps += ddynamic_deps + for dep in ddeps: + if isinstance(dep, PInfo): + deps.append(dep) + else: + method_deps, method_dynamic_deps = _params_depended_on(dep, dynamic, intermediate) + deps += method_deps + dynamic_deps += method_dynamic_deps + return deps, dynamic_deps + + +def _resolve_mcs_deps(obj, resolved, dynamic, intermediate=True): + """ + Resolves constant and dynamic parameter dependencies previously + obtained using the _params_depended_on function. Existing resolved + dependencies are updated with a supplied parameter instance while + dynamic dependencies are resolved if possible. + """ + dependencies = [] + for dep in resolved: + if not issubclass(type(obj), dep.cls): + dependencies.append(dep) + continue + inst = obj if dep.inst is None else dep.inst + dep = PInfo(inst=inst, cls=dep.cls, name=dep.name, + pobj=inst.param[dep.name], what=dep.what) + dependencies.append(dep) + for dep in dynamic: + subresolved, _ = obj.param._spec_to_obj(dep.spec, intermediate=intermediate) + for subdep in subresolved: + if isinstance(subdep, PInfo): + dependencies.append(subdep) + else: + dependencies += _params_depended_on(subdep, intermediate=intermediate)[0] + return dependencies + + +def _skip_event(*events, **kwargs): + """ + Checks whether a subobject event should be skipped. + Returns True if all the values on the new subobject + match the values on the previous subobject. + """ + what = kwargs.get('what', 'value') + changed = kwargs.get('changed') + if changed is None: + return False + for e in events: + for p in changed: + if what == 'value': + old = Undefined if e.old is None else _getattrr(e.old, p, None) + new = Undefined if e.new is None else _getattrr(e.new, p, None) + else: + old = Undefined if e.old is None else _getattrr(e.old.param[p], what, None) + new = Undefined if e.new is None else _getattrr(e.new.param[p], what, None) + if not Comparator.is_equal(old, new): + return False + return True + + +def extract_dependencies(function): + """ + Extract references from a method or function that declares the references. + """ + subparameters = list(function._dinfo['dependencies'])+list(function._dinfo['kw'].values()) + params = [] + for p in subparameters: + if isinstance(p, str): + owner = get_method_owner(function) + *subps, p = p.split('.') + for subp in subps: + owner = getattr(owner, subp, None) + if owner is None: + raise ValueError('Cannot depend on undefined sub-parameter {p!r}.') + if p in owner.param: + pobj = owner.param[p] + if pobj not in params: + params.append(pobj) + else: + for sp in extract_dependencies(getattr(owner, p)): + if sp not in params: + params.append(sp) + elif p not in params: + params.append(p) + return params + + +# Two callers at the module top level to support pickling. +async def _async_caller(*events, what='value', changed=None, callback=None, function=None): + if callback: + callback(*events) + if not _skip_event or not _skip_event(*events, what=what, changed=changed): + await function() + + +def _sync_caller(*events, what='value', changed=None, callback=None, function=None): + if callback: + callback(*events) + if not _skip_event(*events, what=what, changed=changed): + return function() + + +def _m_caller(self, method_name, what='value', changed=None, callback=None): + """ + Wraps a method call adding support for scheduling a callback + before it is executed and skipping events if a subobject has + changed but its values have not. + """ + function = getattr(self, method_name) + _caller = _async_caller if iscoroutinefunction(function) else _sync_caller + caller = partial(_caller, what=what, changed=changed, callback=callback, function=function) + caller._watcher_name = method_name + return caller + + +def _add_doc(obj, docstring): + """Add a docstring to a namedtuple""" + obj.__doc__ = docstring + + +PInfo = namedtuple("PInfo", "inst cls name pobj what") +_add_doc(PInfo, + """ + Object describing something being watched about a Parameter. + + `inst`: Parameterized instance owning the Parameter, or None + + `cls`: Parameterized class owning the Parameter + + `name`: Name of the Parameter being watched + + `pobj`: Parameter object being watched + + `what`: What is being watched on the Parameter (either 'value' or a slot name) + """) + +MInfo = namedtuple("MInfo", "inst cls name method") +_add_doc(MInfo, + """ + Object describing a Parameterized method being watched. + + `inst`: Parameterized instance owning the method, or None + + `cls`: Parameterized class owning the method + + `name`: Name of the method being watched + + `method`: bound method of the object being watched + """) + +DInfo = namedtuple("DInfo", "spec") +_add_doc(DInfo, + """ + Object describing dynamic dependencies. + `spec`: Dependency specification to resolve + """) + +Event = namedtuple("Event", "what name obj cls old new type") +_add_doc(Event, + """ + Object representing an event that triggers a Watcher. + + `what`: What is being watched on the Parameter (either value or a slot name) + + `name`: Name of the Parameter that was set or triggered + + `obj`: Parameterized instance owning the watched Parameter, or None + + `cls`: Parameterized class owning the watched Parameter + + `old`: Previous value of the item being watched + + `new`: New value of the item being watched + + `type`: `triggered` if this event was triggered explicitly), `changed` if + the item was set and watching for `onlychanged`, `set` if the item was set, + or None if type not yet known + """) + +_Watcher = namedtuple("Watcher", "inst cls fn mode onlychanged parameter_names what queued precedence") + +
[docs]class Watcher(_Watcher): + """ + Object declaring a callback function to invoke when an Event is + triggered on a watched item. + + `inst`: Parameterized instance owning the watched Parameter, or + None + + `cls`: Parameterized class owning the watched Parameter + + `fn`: Callback function to invoke when triggered by a watched + Parameter + + `mode`: 'args' for param.watch (call `fn` with PInfo object + positional args), or 'kwargs' for param.watch_values (call `fn` + with <param_name>:<new_value> keywords) + + `onlychanged`: If True, only trigger for actual changes, not + setting to the current value + + `parameter_names`: List of Parameters to watch, by name + + `what`: What to watch on the Parameters (either 'value' or a slot + name) + + `queued`: Immediately invoke callbacks triggered during processing + of an Event (if False), or queue them up for processing + later, after this event has been handled (if True) + + `precedence`: A numeric value which determines the precedence of + the watcher. Lower precedence values are executed + with higher priority. + """ + + def __new__(cls_, *args, **kwargs): + """ + Allows creating Watcher without explicit precedence value. + """ + values = dict(zip(cls_._fields, args)) + values.update(kwargs) + if 'precedence' not in values: + values['precedence'] = 0 + return super().__new__(cls_, **values) + + def __str__(self): + cls = type(self) + attrs = ', '.join([f'{f}={getattr(self, f)!r}' for f in cls._fields]) + return f"{cls.__name__}({attrs})"
+ + + + +class ParameterMetaclass(type): + """ + Metaclass allowing control over creation of Parameter classes. + """ + def __new__(mcs, classname, bases, classdict): + + # store the class's docstring in __classdoc + if '__doc__' in classdict: + classdict['__classdoc']=classdict['__doc__'] + + # when asking for help on Parameter *object*, return the doc slot + classdict['__doc__'] = property(attrgetter('doc')) + + # Compute all slots in order, using a dict later turned into a list + # as it's the fastest way to get an ordered set in Python + all_slots = {} + for bcls in set(chain(*(base.__mro__[::-1] for base in bases))): + all_slots.update(dict.fromkeys(getattr(bcls, '__slots__', []))) + + # To get the benefit of slots, subclasses must themselves define + # __slots__, whether or not they define attributes not present in + # the base Parameter class. That's because a subclass will have + # a __dict__ unless it also defines __slots__. + if '__slots__' not in classdict: + classdict['__slots__'] = [] + else: + all_slots.update(dict.fromkeys(classdict['__slots__'])) + + classdict['_all_slots_'] = list(all_slots) + + # No special handling for a __dict__ slot; should there be? + return type.__new__(mcs, classname, bases, classdict) + + def __getattribute__(mcs,name): + if name=='__doc__': + # when asking for help on Parameter *class*, return the + # stored class docstring + return type.__getattribute__(mcs,'__classdoc') + else: + return type.__getattribute__(mcs,name) + + +class _ParameterBase(metaclass=ParameterMetaclass): + """ + Base Parameter class used to dynamically update the signature of all + the Parameters. + """ + + @classmethod + def _modified_slots_defaults(cls): + defaults = cls._slot_defaults.copy() + defaults['label'] = defaults.pop('_label') + return defaults + + @classmethod + def __init_subclass__(cls): + # _update_signature has been tested against the Parameters available + # in Param, we don't want to break the Parameters created elsewhere + # so wrapping this in a loose try/except. + try: + cls._update_signature() + except Exception: + # The super signature has been changed so we need to get the one + # from the class constructor directly. + cls.__signature__ = inspect.signature(cls.__init__) + + @classmethod + def _update_signature(cls): + defaults = cls._modified_slots_defaults() + new_parameters = {} + + for i, kls in enumerate(cls.mro()): + if kls.__name__.startswith('_'): + continue + sig = inspect.signature(kls.__init__) + for pname, parameter in sig.parameters.items(): + if pname == 'self': + continue + if i >= 1 and parameter.default == inspect.Signature.empty: + continue + if parameter.kind in (inspect.Parameter.VAR_KEYWORD, inspect.Parameter.VAR_POSITIONAL): + continue + if getattr(parameter, 'default', None) is Undefined: + if pname not in defaults: + raise LookupError( + f'Argument {pname!r} of Parameter {cls.__name__!r} has no ' + 'entry in _slot_defaults.' + ) + default = defaults[pname] + if callable(default) and hasattr(default, 'sig'): + default = default.sig + new_parameter = parameter.replace(default=default) + else: + new_parameter = parameter + if i >= 1: + new_parameter = new_parameter.replace(kind=inspect.Parameter.KEYWORD_ONLY) + new_parameters.setdefault(pname, new_parameter) + + def _sorter(p): + if p.default == inspect.Signature.empty: + return 0 + else: + return 1 + + new_parameters = sorted(new_parameters.values(), key=_sorter) + new_sig = sig.replace(parameters=new_parameters) + cls.__signature__ = new_sig + + +
[docs]class Parameter(_ParameterBase): + """ + An attribute descriptor for declaring parameters. + + Parameters are a special kind of class attribute. Setting a + Parameterized class attribute to be a Parameter instance causes + that attribute of the class (and the class's instances) to be + treated as a Parameter. This allows special behavior, including + dynamically generated parameter values, documentation strings, + constant and read-only parameters, and type or range checking at + assignment time. + + For example, suppose someone wants to define two new kinds of + objects Foo and Bar, such that Bar has a parameter delta, Foo is a + subclass of Bar, and Foo has parameters alpha, sigma, and gamma + (and delta inherited from Bar). She would begin her class + definitions with something like this:: + + class Bar(Parameterized): + delta = Parameter(default=0.6, doc='The difference between steps.') + ... + class Foo(Bar): + alpha = Parameter(default=0.1, doc='The starting value.') + sigma = Parameter(default=0.5, doc='The standard deviation.', + constant=True) + gamma = Parameter(default=1.0, doc='The ending value.') + ... + + Class Foo would then have four parameters, with delta defaulting + to 0.6. + + Parameters have several advantages over plain attributes: + + 1. Parameters can be set automatically when an instance is + constructed: The default constructor for Foo (and Bar) will + accept arbitrary keyword arguments, each of which can be used + to specify the value of a Parameter of Foo (or any of Foo's + superclasses). E.g., if a script does this:: + + myfoo = Foo(alpha=0.5) + + myfoo.alpha will return 0.5, without the Foo constructor + needing special code to set alpha. + + If Foo implements its own constructor, keyword arguments will + still be accepted if the constructor accepts a dictionary of + keyword arguments (as in ``def __init__(self,**params):``), and + then each class calls its superclass (as in + ``super(Foo,self).__init__(**params)``) so that the + Parameterized constructor will process the keywords. + + 2. A Parameterized class need specify only the attributes of a + Parameter whose values differ from those declared in + superclasses; the other values will be inherited. E.g. if Foo + declares:: + + delta = Parameter(default=0.2) + + the default value of 0.2 will override the 0.6 inherited from + Bar, but the doc will be inherited from Bar. + + 3. The Parameter descriptor class can be subclassed to provide + more complex behavior, allowing special types of parameters + that, for example, require their values to be numbers in + certain ranges, generate their values dynamically from a random + distribution, or read their values from a file or other + external source. + + 4. The attributes associated with Parameters provide enough + information for automatically generating property sheets in + graphical user interfaces, allowing Parameterized instances to + be edited by users. + + Note that Parameters can only be used when set as class attributes + of Parameterized classes. Parameters used as standalone objects, + or as class attributes of non-Parameterized classes, will not have + the behavior described here. + """ + + # Because they implement __get__ and __set__, Parameters are known + # as 'descriptors' in Python; see "Implementing Descriptors" and + # "Invoking Descriptors" in the 'Customizing attribute access' + # section of the Python reference manual: + # http://docs.python.org/ref/attribute-access.html + # + # Overview of Parameters for programmers + # ====================================== + # + # Consider the following code: + # + # + # class A(Parameterized): + # p = Parameter(default=1) + # + # a1 = A() + # a2 = A() + # + # + # * a1 and a2 share one Parameter object (A.__dict__['p']). + # + # * The default (class) value of p is stored in this Parameter + # object (A.__dict__['p'].default). + # + # * If the value of p is set on a1 (e.g. a1.p=2), a1's value of p + # is stored in a1 itself (a1._param__private.values['p']) + # + # * When a1.p is requested, a1._param__private.values['p'] is + # returned. When a2.p is requested, 'p' is not found in + # a1._param__private.values, so A.__dict__['p'].default (i.e. A.p) is + # returned instead. + # + # + # Be careful when referring to the 'name' of a Parameter: + # + # * A Parameterized class has a name for the attribute which is + # being represented by the Parameter ('p' in the example above); + # in the code, this is called the 'name'. + # + # * When a Parameterized instance has its own local value for a + # parameter, it is stored as 'p._param__private.values[X]' where X is the + # name of the Parameter + + + # So that the extra features of Parameters do not require a lot of + # overhead, Parameters are implemented using __slots__ (see + # http://www.python.org/doc/2.4/ref/slots.html). Instead of having + # a full Python dictionary associated with each Parameter instance, + # Parameter instances have an enumerated list (named __slots__) of + # attributes, and reserve just enough space to store these + # attributes. Using __slots__ requires special support for + # operations to copy and restore Parameters (e.g. for Python + # persistent storage pickling); see __getstate__ and __setstate__. + __slots__ = ['name', 'default', 'doc', + 'precedence', 'instantiate', 'constant', 'readonly', + 'pickle_default_value', 'allow_None', 'per_instance', + 'watchers', 'owner', 'allow_refs', 'nested_refs', '_label'] + + # Note: When initially created, a Parameter does not know which + # Parameterized class owns it, nor does it know its names + # (attribute name, internal name). Once the owning Parameterized + # class is created, owner, and name are + # set. + + _serializers = {'json': serializer.JSONSerialization} + + _slot_defaults = dict( + default=None, precedence=None, doc=None, _label=None, instantiate=False, + constant=False, readonly=False, pickle_default_value=True, allow_None=False, + per_instance=True, allow_refs=False, nested_refs=False + ) + + # Parameters can be updated during Parameterized class creation when they + # are defined multiple times in a class hierarchy. We have to record which + # Parameter slots require the default value to be re-validated. Any slots + # in this list do not have to trigger such re-validation. + _non_validated_slots = ['_label', 'doc', 'name', 'precedence', + 'constant', 'pickle_default_value', + 'watchers', 'owner'] + + @typing.overload + def __init__( + self, + default=None, *, + doc=None, label=None, precedence=None, instantiate=False, constant=False, + readonly=False, pickle_default_value=True, allow_None=False, per_instance=True, + allow_refs=False, nested_refs=False + ): + ... + +
[docs] @_deprecate_positional_args + def __init__(self, default=Undefined, *, doc=Undefined, # pylint: disable-msg=R0913 + label=Undefined, precedence=Undefined, + instantiate=Undefined, constant=Undefined, readonly=Undefined, + pickle_default_value=Undefined, allow_None=Undefined, + per_instance=Undefined, allow_refs=Undefined, nested_refs=Undefined): + + """Initialize a new Parameter object and store the supplied attributes: + + default: the owning class's value for the attribute represented + by this Parameter, which can be overridden in an instance. + + doc: docstring explaining what this parameter represents. + + label: optional text label to be used when this Parameter is + shown in a listing. If no label is supplied, the attribute name + for this parameter in the owning Parameterized object is used. + + precedence: a numeric value, usually in the range 0.0 to 1.0, + which allows the order of Parameters in a class to be defined in + a listing or e.g. in GUI menus. A negative precedence indicates + a parameter that should be hidden in such listings. + + instantiate: controls whether the value of this Parameter will + be deepcopied when a Parameterized object is instantiated (if + True), or if the single default value will be shared by all + Parameterized instances (if False). For an immutable Parameter + value, it is best to leave instantiate at the default of + False, so that a user can choose to change the value at the + Parameterized instance level (affecting only that instance) or + at the Parameterized class or superclass level (affecting all + existing and future instances of that class or superclass). For + a mutable Parameter value, the default of False is also appropriate + if you want all instances to share the same value state, e.g. if + they are each simply referring to a single global object like + a singleton. If instead each Parameterized should have its own + independently mutable value, instantiate should be set to + True, but note that there is then no simple way to change the + value of this Parameter at the class or superclass level, + because each instance, once created, will then have an + independently instantiated value. + + constant: if true, the Parameter value can be changed only at + the class level or in a Parameterized constructor call. The + value is otherwise constant on the Parameterized instance, + once it has been constructed. + + readonly: if true, the Parameter value cannot ordinarily be + changed by setting the attribute at the class or instance + levels at all. The value can still be changed in code by + temporarily overriding the value of this slot and then + restoring it, which is useful for reporting values that the + _user_ should never change but which do change during code + execution. + + pickle_default_value: whether the default value should be + pickled. Usually, you would want the default value to be pickled, + but there are rare cases where that would not be the case (e.g. + for file search paths that are specific to a certain system). + + per_instance: whether a separate Parameter instance will be + created for every Parameterized instance. True by default. + If False, all instances of a Parameterized class will share + the same Parameter object, including all validation + attributes (bounds, etc.). See also instantiate, which is + conceptually similar but affects the Parameter value rather + than the Parameter object. + + allow_None: if True, None is accepted as a valid value for + this Parameter, in addition to any other values that are + allowed. If the default value is defined as None, allow_None + is set to True automatically. + + allow_refs: if True allows automatically linking parameter + references to this Parameter, i.e. the parameter value will + automatically reflect the current value of the reference that + is passed in. + + nested_refs: if True and allow_refs=True then even nested objects + such as dictionaries, lists, slices, tuples and sets will be + inspected for references and will be automatically resolved. + + default, doc, and precedence all default to None, which allows + inheritance of Parameter slots (attributes) from the owning-class' + class hierarchy (see ParameterizedMetaclass). + """ + + self.name = None + self.owner = None + self.allow_refs = allow_refs + self.nested_refs = nested_refs + self.precedence = precedence + self.default = default + self.doc = doc + self.constant = constant is True or readonly is True # readonly => constant + self.readonly = readonly + self._label = label + self._set_instantiate(instantiate) + self.pickle_default_value = pickle_default_value + self._set_allow_None(allow_None) + self.watchers = {} + self.per_instance = per_instance
+ + @classmethod + def serialize(cls, value): + "Given the parameter value, return a Python value suitable for serialization" + return value + + @classmethod + def deserialize(cls, value): + "Given a serializable Python value, return a value that the parameter can be set to" + return value + + def schema(self, safe=False, subset=None, mode='json'): + if serializer is None: + raise ImportError('Cannot import serializer.py needed to generate schema') + if mode not in self._serializers: + raise KeyError(f'Mode {mode!r} not in available serialization formats {list(self._serializers.keys())!r}') + return self._serializers[mode].param_schema(self.__class__.__name__, self, + safe=safe, subset=subset) + + @property + def rx(self): + from .reactive import reactive_ops + return reactive_ops(self) + + @property + def label(self): + if self.name and self._label is None: + return label_formatter(self.name) + else: + return self._label + + @label.setter + def label(self, val): + self._label = val + + def _set_allow_None(self, allow_None): + # allow_None is set following these rules (last takes precedence): + # 1. to False by default + # 2. to the value provided in the constructor, if any + # 3. to True if default is None + if self.default is None: + self.allow_None = True + elif allow_None is not Undefined: + self.allow_None = allow_None + else: + self.allow_None = self._slot_defaults['allow_None'] + + def _set_instantiate(self,instantiate): + """Constant parameters must be instantiated.""" + # instantiate doesn't actually matter for read-only + # parameters, since they can't be set even on a class. But + # having this code avoids needless instantiation. + if self.readonly: + self.instantiate = False + elif instantiate is not Undefined: + self.instantiate = instantiate + else: + # Default value + self.instantiate = self._slot_defaults['instantiate'] + + def __setattr__(self, attribute, value): + if attribute == 'name': + name = getattr(self, 'name', None) + if name is not None and value != name: + raise AttributeError("Parameter name cannot be modified after " + "it has been bound to a Parameterized.") + + is_slot = attribute in self.__class__._all_slots_ + has_watcher = attribute != "default" and attribute in getattr(self, 'watchers', []) + if not (is_slot or has_watcher): + # Return early if attribute is not a slot + return super().__setattr__(attribute, value) + + # Otherwise get the old value so we can call watcher/on_set + old = getattr(self, attribute, NotImplemented) + if is_slot: + try: + self._on_set(attribute, old, value) + except AttributeError: + pass + + super().__setattr__(attribute, value) + if has_watcher and old is not NotImplemented: + self._trigger_event(attribute, old, value) + + def _trigger_event(self, attribute, old, new): + event = Event(what=attribute, name=self.name, obj=None, cls=self.owner, + old=old, new=new, type=None) + for watcher in self.watchers[attribute]: + self.owner.param._call_watcher(watcher, event) + if not self.owner.param._BATCH_WATCH: + self.owner.param._batch_call_watchers() + + def __getattribute__(self, key): + """ + Allow slot values to be Undefined in an "unbound" parameter, i.e. one + that is not (yet) owned by a Parameterized object, in which case their + value will be retrieved from the _slot_defaults dictionary. + """ + v = object.__getattribute__(self, key) + # Safely checks for name (avoiding recursion) to decide if this object is unbound + if v is Undefined and key != "name" and getattr(self, "name", None) is None: + try: + v = self._slot_defaults[key] + except KeyError as e: + raise KeyError( + f'Slot {key!r} on unbound parameter {self.__class__.__name__!r} ' + 'has no default value defined in `_slot_defaults`' + ) from e + if callable(v): + v = v(self) + return v + + def _on_set(self, attribute, old, value): + """ + Can be overridden on subclasses to handle changes when parameter + attribute is set. + """ + + def _update_state(self): + """ + Can be overridden on subclasses to update a Parameter state, i.e. slot + values, after the slot values have been set in the inheritance procedure. + """ + + def __get__(self, obj, objtype): # pylint: disable-msg=W0613 + """ + Return the value for this Parameter. + + If called for a Parameterized class, produce that + class's value (i.e. this Parameter object's 'default' + attribute). + + If called for a Parameterized instance, produce that + instance's value, if one has been set - otherwise produce the + class's value (default). + """ + if obj is None: # e.g. when __get__ called for a Parameterized class + result = self.default + else: + # Attribute error when .values does not exist (_ClassPrivate) + # and KeyError when there's no cached value for this parameter. + try: + result = obj._param__private.values[self.name] + except (AttributeError, KeyError): + result = self.default + return result + + @instance_descriptor + def __set__(self, obj, val): + """ + Set the value for this Parameter. + + If called for a Parameterized class, set that class's + value (i.e. set this Parameter object's 'default' attribute). + + If called for a Parameterized instance, set the value of + this Parameter on that instance (i.e. in the instance's + `values` dictionary located in the private namespace `_param__private`, + under the parameter's name). + + If the Parameter's constant attribute is True, only allows + the value to be set for a Parameterized class or on + uninitialized Parameterized instances. + + If the Parameter's readonly attribute is True, only allows the + value to be specified in the Parameter declaration inside the + Parameterized source code. A read-only parameter also + cannot be set on a Parameterized class. + + Note that until we support some form of read-only + object, it is still possible to change the attributes of the + object stored in a constant or read-only Parameter (e.g. one + item in a list). + """ + name = self.name + if obj is not None and self.allow_refs and obj._param__private.initialized and name not in obj._param__private.syncing: + ref, deps, val, _ = obj.param._resolve_ref(self, val) + refs = obj._param__private.refs + if ref is not None: + self.owner.param._update_ref(name, ref) + elif name in refs: + del refs[name] + + # Deprecated Number set_hook called here to avoid duplicating setter + if hasattr(self, 'set_hook'): + val = self.set_hook(obj, val) + if self.set_hook is not _identity_hook: + # PARAM3_DEPRECATION + warnings.warn( + 'Number.set_hook has been deprecated.', + category=_ParamDeprecationWarning, + stacklevel=6, + ) + + self._validate(val) + + _old = NotImplemented + # obj can be None if __set__ is called for a Parameterized class + if self.constant or self.readonly: + if self.readonly: + raise TypeError("Read-only parameter '%s' cannot be modified" % name) + elif obj is None: + _old = self.default + self.default = val + elif not obj._param__private.initialized: + _old = obj._param__private.values.get(self.name, self.default) + obj._param__private.values[self.name] = val + else: + _old = obj._param__private.values.get(self.name, self.default) + if val is not _old: + raise TypeError("Constant parameter '%s' cannot be modified" % name) + else: + if obj is None: + _old = self.default + self.default = val + else: + # When setting a Parameter before calling super. + if not isinstance(obj._param__private, _InstancePrivate): + obj._param__private = _InstancePrivate() + _old = obj._param__private.values.get(name, self.default) + obj._param__private.values[name] = val + self._post_setter(obj, val) + + if obj is not None: + if not hasattr(obj, '_param__private') or not getattr(obj._param__private, 'initialized', False): + return + obj.param._update_deps(name) + + if obj is None: + watchers = self.watchers.get("value") + elif name in obj._param__private.watchers: + watchers = obj._param__private.watchers[name].get('value') + if watchers is None: + watchers = self.watchers.get("value") + else: + watchers = None + + obj = self.owner if obj is None else obj + + if obj is None or not watchers: + return + + event = Event(what='value', name=name, obj=obj, cls=self.owner, + old=_old, new=val, type=None) + + # Copy watchers here since they may be modified inplace during iteration + for watcher in sorted(watchers, key=lambda w: w.precedence): + obj.param._call_watcher(watcher, event) + if not obj.param._BATCH_WATCH: + obj.param._batch_call_watchers() + + def _validate_value(self, value, allow_None): + """Implements validation for parameter value""" + + def _validate(self, val): + """Implements validation for the parameter value and attributes""" + self._validate_value(val, self.allow_None) + + def _post_setter(self, obj, val): + """Called after the parameter value has been validated and set""" + + def __delete__(self,obj): + raise TypeError("Cannot delete '%s': Parameters deletion not allowed." % self.name) + + def _set_names(self, attrib_name): + if None not in (self.owner, self.name) and attrib_name != self.name: + raise AttributeError('The {} parameter {!r} has already been ' + 'assigned a name by the {} class, ' + 'could not assign new name {!r}. Parameters ' + 'may not be shared by multiple classes; ' + 'ensure that you create a new parameter ' + 'instance for each new class.'.format(type(self).__name__, self.name, + self.owner.name, attrib_name)) + self.name = attrib_name + + def __getstate__(self): + """ + All Parameters have slots, not a dict, so we have to support + pickle and deepcopy ourselves. + """ + return {slot: getattr(self, slot) for slot in self.__class__._all_slots_} + + def __setstate__(self,state): + # set values of __slots__ (instead of in non-existent __dict__) + for k, v in state.items(): + setattr(self, k, v)
+ + +# Define one particular type of Parameter that is used in this file +
[docs]class String(Parameter): + r""" + A String Parameter, with a default value and optional regular expression (regex) matching. + + Example of using a regex to implement IPv4 address matching:: + + class IPAddress(String): + '''IPv4 address as a string (dotted decimal notation)''' + def __init__(self, default="0.0.0.0", allow_None=False, **kwargs): + ip_regex = r'^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$' + super(IPAddress, self).__init__(default=default, regex=ip_regex, **kwargs) + + """ + + __slots__ = ['regex'] + + _slot_defaults = _dict_update(Parameter._slot_defaults, default="", regex=None) + + @typing.overload + def __init__( + self, + default="", *, regex=None, + doc=None, label=None, precedence=None, instantiate=False, constant=False, + readonly=False, pickle_default_value=True, allow_None=False, per_instance=True, + allow_refs=False, nested_refs=False + ): + ... + +
[docs] @_deprecate_positional_args + def __init__(self, default=Undefined, *, regex=Undefined, **kwargs): + super().__init__(default=default, **kwargs) + self.regex = regex + self._validate(self.default)
+ + def _validate_regex(self, val, regex): + if (val is None and self.allow_None): + return + if regex is not None and re.match(regex, val) is None: + raise ValueError( + f'{_validate_error_prefix(self)} value {val!r} does not ' + f'match regex {regex!r}.' + ) + + def _validate_value(self, val, allow_None): + if allow_None and val is None: + return + if not isinstance(val, str): + raise ValueError( + f'{_validate_error_prefix(self)} only takes a string value, ' + f'not value of {type(val)}.' + ) + + def _validate(self, val): + self._validate_value(val, self.allow_None) + self._validate_regex(val, self.regex)
+ + +class shared_parameters: + """ + Context manager to share parameter instances when creating + multiple Parameterized objects of the same type. Parameter default + values are instantiated once and cached to be reused when another + Parameterized object of the same type is instantiated. + Can be useful to easily modify large collections of Parameterized + objects at once and can provide a significant speedup. + """ + + _share = False + _shared_cache = {} + + def __enter__(self): + shared_parameters._share = True + + def __exit__(self, exc_type, exc_val, exc_tb): + shared_parameters._share = False + shared_parameters._shared_cache = {} + + +def as_uninitialized(fn): + """ + Decorator: call fn with the parameterized_instance's + initialization flag set to False, then revert the flag. + + (Used to decorate Parameterized methods that must alter + a constant Parameter.) + """ + @wraps(fn) + def override_initialization(self_,*args,**kw): + parameterized_instance = self_.self + original_initialized = parameterized_instance._param__private.initialized + parameterized_instance._param__private.initialized = False + ret = fn(self_, *args, **kw) + parameterized_instance._param__private.initialized = original_initialized + return ret + return override_initialization + + +class Comparator: + """ + Comparator defines methods for determining whether two objects + should be considered equal. It works by registering custom + comparison functions, which may either be registed by type or with + a predicate function. If no matching comparison can be found for + the two objects the comparison will return False. + + If registered by type the Comparator will check whether both + objects are of that type and apply the comparison. If the equality + function is instead registered with a function it will call the + function with each object individually to check if the comparison + applies. This is useful for defining comparisons for objects + without explicitly importing them. + + To use the Comparator simply call the is_equal function. + """ + + equalities = { + numbers.Number: operator.eq, + str: operator.eq, + bytes: operator.eq, + type(None): operator.eq, + lambda o: hasattr(o, '_infinitely_iterable'): operator.eq, # Time + } + equalities.update({dtt: operator.eq for dtt in dt_types}) + + @classmethod + def is_equal(cls, obj1, obj2): + for eq_type, eq in cls.equalities.items(): + try: + are_instances = isinstance(obj1, eq_type) and isinstance(obj2, eq_type) + except TypeError: + pass + else: + if are_instances: + return eq(obj1, obj2) + if isinstance(eq_type, FunctionType) and eq_type(obj1) and eq_type(obj2): + return eq(obj1, obj2) + if isinstance(obj2, (list, set, tuple)): + return cls.compare_iterator(obj1, obj2) + elif isinstance(obj2, dict): + return cls.compare_mapping(obj1, obj2) + return False + + @classmethod + def compare_iterator(cls, obj1, obj2): + if type(obj1) != type(obj2) or len(obj1) != len(obj2): + return False + for o1, o2 in zip(obj1, obj2): + if not cls.is_equal(o1, o2): + return False + return True + + @classmethod + def compare_mapping(cls, obj1, obj2): + if type(obj1) != type(obj2) or len(obj1) != len(obj2): return False + for k in obj1: + if k in obj2: + if not cls.is_equal(obj1[k], obj2[k]): + return False + else: + return False + return True + + +class _ParametersRestorer: + """ + Context-manager to handle the reset of parameter values after an update. + """ + + def __init__(self, *, parameters, restore): + self._parameters = parameters + self._restore = restore + + def __enter__(self): + return self._restore + + def __exit__(self, exc_type, exc_value, exc_tb): + try: + self._parameters._update(self._restore) + finally: + self._restore = {} + + +class Parameters: + """Object that holds the namespace and implementation of Parameterized + methods as well as any state that is not in __slots__ or the + Parameters themselves. + + Exists at both the metaclass level (instantiated by the metaclass) + and at the instance level. Can contain state specific to either the + class or the instance as necessary. + """ + + def __init__(self_, cls, self=None): + """ + cls is the Parameterized class which is always set. + self is the instance if set. + """ + self_.cls = cls + self_.self = self + + @property + def _BATCH_WATCH(self_): + return self_.self_or_cls._param__private.parameters_state['BATCH_WATCH'] + + @_BATCH_WATCH.setter + def _BATCH_WATCH(self_, value): + self_.self_or_cls._param__private.parameters_state['BATCH_WATCH'] = value + + @property + def _TRIGGER(self_): + return self_.self_or_cls._param__private.parameters_state['TRIGGER'] + + @_TRIGGER.setter + def _TRIGGER(self_, value): + self_.self_or_cls._param__private.parameters_state['TRIGGER'] = value + + @property + def _events(self_): + return self_.self_or_cls._param__private.parameters_state['events'] + + @_events.setter + def _events(self_, value): + self_.self_or_cls._param__private.parameters_state['events'] = value + + @property + def _state_watchers(self_): + return self_.self_or_cls._param__private.parameters_state['watchers'] + + @_state_watchers.setter + def _state_watchers(self_, value): + self_.self_or_cls._param__private.parameters_state['watchers'] = value + + @property + def watchers(self_): + """Dictionary of instance watchers.""" + if self_.self is None: + raise TypeError('Accessing `.param.watchers` is only supported on a Parameterized instance, not class.') + return self_.self._param__private.watchers + + @watchers.setter + def watchers(self_, value): + if self_.self is None: + raise TypeError('Setting `.param.watchers` is only supported on a Parameterized instance, not class.') + self_.self._param__private.watchers = value + + @property + def self_or_cls(self_): + return self_.cls if self_.self is None else self_.self + + def __setstate__(self, state): + # Set old parameters state on Parameterized.parameters_state + self_, cls = state.get('self'), state.get('cls') + self_or_cls = self_ if self_ is not None else cls + for k in self_or_cls._param__private.parameters_state: + key = '_'+k + if key in state: + self_or_cls._param__private.parameters_state[k] = state.pop(key) + for k, v in state.items(): + setattr(self, k, v) + + def __getitem__(self_, key): + """ + Returns the class or instance parameter + """ + inst = self_.self + params = self_ if inst is None else inst.param + p = params.objects(False)[key] + return p if inst is None else _instantiated_parameter(inst, p) + + def __dir__(self_): + """ + Adds parameters to dir + """ + return super().__dir__() + list(self_) + + def __iter__(self_): + """ + Iterates over the parameters on this object. + """ + yield from self_.objects(instance=False) + + def __contains__(self_, param): + return param in list(self_) + + def __getattr__(self_, attr): + """ + Extends attribute access to parameter objects. + """ + cls = self_.__dict__.get('cls') + if cls is None: # Class not initialized + raise AttributeError + + params = list(cls._param__private.params) + if not params: + params = [n for class_ in classlist(cls) for n, v in class_.__dict__.items() + if isinstance(v, Parameter)] + + if attr in params: + return self_.__getitem__(attr) + elif self_.self is None: + raise AttributeError(f"type object '{self_.cls.__name__}.param' has no attribute {attr!r}") + else: + raise AttributeError(f"'{self_.cls.__name__}.param' object has no attribute {attr!r}") + + @as_uninitialized + def _set_name(self_, name): + self_.self.name = name + + @as_uninitialized + def _generate_name(self_): + self_._set_name('%s%05d' % (self_.cls.__name__, object_count)) + + @as_uninitialized + def _setup_params(self_, **params): + """ + Initialize default and keyword parameter values. + + First, ensures that values for all Parameters with 'instantiate=True' + (typically used for mutable Parameters) are copied directly into each object, + to ensure that there is an independent copy of the value (to avoid surprising + aliasing errors). Second, ensures that Parameters with 'constant=True' are + referenced on the instance, to make sure that setting a constant + Parameter on the class doesn't affect already created instances. Then + sets each of the keyword arguments, raising when any of them are not + defined as parameters. + """ + self = self_.self + ## Deepcopy all 'instantiate=True' parameters + params_to_deepcopy = {} + params_to_ref = {} + for pname, p in self_.objects(instance=False).items(): + if p.instantiate and pname != "name": + params_to_deepcopy[pname] = p + elif p.constant and pname != 'name': + params_to_ref[pname] = p + + for p in params_to_deepcopy.values(): + self_._instantiate_param(p) + for p in params_to_ref.values(): + self_._instantiate_param(p, deepcopy=False) + + ## keyword arg setting + deps, refs = {}, {} + objects = self.param.objects(instance=False) + for name, val in params.items(): + desc = self_.cls.get_param_descriptor(name)[0] # pylint: disable-msg=E1101 + if not desc: + raise TypeError( + f"{self.__class__.__name__}.__init__() got an unexpected " + f"keyword argument {name!r}" + ) + + pobj = objects.get(name) + if pobj is None or not pobj.allow_refs: + # Until Parameter.allow_refs=True by default we have to + # speculatively evaluate a values to check whether they + # contain a reference and warn the user that the + # behavior may change in future. + if name not in self_.cls._param__private.explicit_no_refs: + try: + ref, _, resolved, _ = self_._resolve_ref(pobj, val) + except Exception: + ref = None + if ref: + warnings.warn( + f"Parameter {name!r} on {pobj.owner} is being given a valid parameter " + f"reference {val} but is implicitly allow_refs=False. " + "In future allow_refs will be enabled by default and " + f"the reference {val} will be resolved to its underlying " + f"value {resolved}. Please explicitly set allow_ref on the " + "Parameter definition to declare whether references " + "should be resolved or not.", + category=_ParamFutureWarning, + stacklevel=4, + ) + setattr(self, name, val) + continue + + # Resolve references + ref, ref_deps, resolved, is_async = self_._resolve_ref(pobj, val) + if ref is not None: + refs[name] = ref + deps[name] = ref_deps + if not is_async: + setattr(self, name, resolved) + return refs, deps + + def _setup_refs(self_, refs): + groups = defaultdict(list) + for pname, subrefs in refs.items(): + for p in subrefs: + + if isinstance(p, Parameter): + groups[p.owner].append((pname, p.name)) + else: + for sp in extract_dependencies(p): + groups[sp.owner].append((pname, sp.name)) + for owner, pnames in groups.items(): + refnames, pnames = zip(*pnames) + self_.self._param__private.ref_watchers.append(( + refnames, + owner.param._watch(self_._sync_refs, list(set(pnames)), precedence=-1) + )) + + def _update_ref(self_, name, ref): + for _, watcher in self_.self._param__private.ref_watchers: + dep_obj = watcher.cls if watcher.inst is None else watcher.inst + dep_obj.param.unwatch(watcher) + self_.self._param__private.ref_watchers = [] + refs = dict(self_.self._param__private.refs, **{name: ref}) + deps = {name: resolve_ref(ref) for name, ref in refs.items()} + self_._setup_refs(deps) + self_.self._param__private.refs = refs + + def _sync_refs(self_, *events): + updates = {} + for pname, ref in self_.self._param__private.refs.items(): + # Skip updating value if dependency has not changed + deps = resolve_ref(ref, self_[pname].nested_refs) + is_async = iscoroutinefunction(ref) + if not any((dep.owner is e.obj and dep.name == e.name) for dep in deps for e in events) and not is_async: + continue + + new_val = resolve_value(ref) + if is_async: + async_executor(partial(self_._async_ref, pname, new_val)) + continue + + updates[pname] = new_val + + with edit_constant(self_.self): + with _syncing(self_.self, updates): + self_.update(updates) + + def _resolve_ref(self_, pobj, value): + is_async = iscoroutinefunction(value) + deps = resolve_ref(value, recursive=pobj.nested_refs) + if not deps and not is_async: + return None, None, value, False + ref = value + value = resolve_value(value) + if is_async: + async_executor(partial(self_._async_ref, pobj.name, value)) + value = None + return ref, deps, value, is_async + + async def _async_ref(self_, pname, awaitable): + if not self_.self._param__private.initialized: + async_executor(partial(self_._async_ref, pname, awaitable)) + return + if pname in self_.self._param__private.async_refs: + self_.self._param__private.async_refs[pname].cancel() + self_.self._param__private.async_refs[pname] = asyncio.current_task() + try: + if isinstance(awaitable, types.AsyncGeneratorType): + async for new_obj in awaitable: + with _syncing(self_.self, (pname,)): + self_.update({pname: new_obj}) + else: + with _syncing(self_.self, (pname,)): + self_.update({pname: await awaitable}) + except Exception as e: + raise e + finally: + del self_.self._param__private.async_refs[pname] + + @classmethod + def _changed(cls, event): + """ + Predicate that determines whether a Event object has actually + changed such that old != new. + """ + return not Comparator.is_equal(event.old, event.new) + + def _instantiate_param(self_, param_obj, dict_=None, key=None, deepcopy=True): + # deepcopy or store a reference to reference param_obj.default into + # self._param__private.values (or dict_ if supplied) under the + # parameter's name (or key if supplied) + instantiator = copy.deepcopy if deepcopy else lambda o: o + self = self_.self + dict_ = dict_ or self._param__private.values + key = key or param_obj.name + if shared_parameters._share: + param_key = (str(type(self)), param_obj.name) + if param_key in shared_parameters._shared_cache: + new_object = shared_parameters._shared_cache[param_key] + else: + new_object = instantiator(param_obj.default) + shared_parameters._shared_cache[param_key] = new_object + else: + new_object = instantiator(param_obj.default) + + dict_[key] = new_object + + if isinstance(new_object, Parameterized): + global object_count + object_count += 1 + # Writes over name given to the original object; + # could instead have kept the same name + new_object.param._generate_name() + + def _update_deps(self_, attribute=None, init=False): + obj = self_.self + init_methods = [] + for method, queued, on_init, constant, dynamic in type(obj).param._depends['watch']: + # On initialization set up constant watchers; otherwise + # clean up previous dynamic watchers for the updated attribute + dynamic = [d for d in dynamic if attribute is None or d.spec.split(".")[0] == attribute] + if init: + constant_grouped = defaultdict(list) + for dep in _resolve_mcs_deps(obj, constant, []): + constant_grouped[(id(dep.inst), id(dep.cls), dep.what)].append((None, dep)) + for group in constant_grouped.values(): + self_._watch_group(obj, method, queued, group) + m = getattr(self_.self, method) + if on_init and m not in init_methods: + init_methods.append(m) + elif dynamic: + for w in obj._param__private.dynamic_watchers.pop(method, []): + (w.cls if w.inst is None else w.inst).param.unwatch(w) + else: + continue + + # Resolve dynamic dependencies one-by-one to be able to trace their watchers + grouped = defaultdict(list) + for ddep in dynamic: + for dep in _resolve_mcs_deps(obj, [], [ddep]): + grouped[(id(dep.inst), id(dep.cls), dep.what)].append((ddep, dep)) + + for group in grouped.values(): + watcher = self_._watch_group(obj, method, queued, group, attribute) + obj._param__private.dynamic_watchers[method].append(watcher) + for m in init_methods: + m() + + def _resolve_dynamic_deps(self, obj, dynamic_dep, param_dep, attribute): + """ + If a subobject whose parameters are being depended on changes + we should only trigger events if the actual parameter values + of the new object differ from those on the old subobject, + therefore we accumulate parameters to compare on a subobject + change event. + + Additionally we need to make sure to notify the parent object + if a subobject changes so the dependencies can be + reinitialized so we return a callback which updates the + dependencies. + """ + subobj = obj + subobjs = [obj] + for subpath in dynamic_dep.spec.split('.')[:-1]: + subobj = getattr(subobj, subpath.split(':')[0], None) + subobjs.append(subobj) + + dep_obj = param_dep.cls if param_dep.inst is None else param_dep.inst + if dep_obj not in subobjs[:-1]: + return None, None, param_dep.what + + depth = subobjs.index(dep_obj) + callback = None + if depth > 0: + def callback(*events): + """ + If a subobject changes, we need to notify the main + object to update the dependencies. + """ + obj.param._update_deps(attribute) + + p = '.'.join(dynamic_dep.spec.split(':')[0].split('.')[depth+1:]) + if p == 'param': + subparams = [sp for sp in list(subobjs[-1].param)] + else: + subparams = [p] + + if ':' in dynamic_dep.spec: + what = dynamic_dep.spec.split(':')[-1] + else: + what = param_dep.what + + return subparams, callback, what + + def _watch_group(self_, obj, name, queued, group, attribute=None): + """ + Sets up a watcher for a group of dependencies. Ensures that + if the dependency was dynamically generated we check whether + a subobject change event actually causes a value change and + that we update the existing watchers, i.e. clean up watchers + on the old subobject and create watchers on the new subobject. + """ + dynamic_dep, param_dep = group[0] + dep_obj = param_dep.cls if param_dep.inst is None else param_dep.inst + params = [] + for _, g in group: + if g.name not in params: + params.append(g.name) + + if dynamic_dep is None: + subparams, callback, what = None, None, param_dep.what + else: + subparams, callback, what = self_._resolve_dynamic_deps( + obj, dynamic_dep, param_dep, attribute) + + mcaller = _m_caller(obj, name, what, subparams, callback) + return dep_obj.param._watch( + mcaller, params, param_dep.what, queued=queued, precedence=-1) + + @_recursive_repr() + def _repr_html_(self_, open=True): + return _parameterized_repr_html(self_.self_or_cls, open) + + # Classmethods + + # PARAM3_DEPRECATION +
[docs] @_deprecated(extra_msg="""Use instead `for k,v in p.param.objects().items(): print(f"{p.__class__.name}.{k}={repr(v.default)}")`""") + def print_param_defaults(self_): + """Print the default values of all cls's Parameters. + + .. deprecated:: 1.12.0 + Use instead `for k,v in p.param.objects().items(): print(f"{p.__class__.name}.{k}={repr(v.default)}")` + """ + cls = self_.cls + for key,val in cls.__dict__.items(): + if isinstance(val,Parameter): + print(cls.__name__+'.'+key+ '='+ repr(val.default))
+ + # PARAM3_DEPRECATION +
[docs] @_deprecated(extra_msg="Use instead `p.param.default =`") + def set_default(self_,param_name,value): + """ + Set the default value of param_name. + + Equivalent to setting param_name on the class. + + .. deprecated:: 1.12.0 + Use instead `p.param.default =` + """ + cls = self_.cls + setattr(cls,param_name,value)
+ +
[docs] def add_parameter(self_, param_name, param_obj): + """ + Add a new Parameter object into this object's class. + + Should result in a Parameter equivalent to one declared + in the class's source code. + """ + # Could have just done setattr(cls,param_name,param_obj), + # which is supported by the metaclass's __setattr__ , but + # would need to handle the params() cache as well + # (which is tricky but important for startup speed). + cls = self_.cls + type.__setattr__(cls,param_name,param_obj) + ParameterizedMetaclass._initialize_parameter(cls,param_name,param_obj) + # delete cached params() + cls._param__private.params.clear()
+ + # PARAM3_DEPRECATION + @_deprecated(extra_msg="Use instead `.param.add_parameter`") + def _add_parameter(self_,param_name, param_obj): + """Add a new Parameter object into this object's class. + + .. deprecated :: 1.12.0 + """ + return self_.add_parameter(param_name, param_obj) + + # PARAM3_DEPRECATION +
[docs] @_deprecated(extra_msg="Use instead `.param.values()` or `.param['param']`") + def params(self_, parameter_name=None): + """ + Return the Parameters of this class as the + dictionary {name: parameter_object} + + Includes Parameters from this class and its + superclasses. + + .. deprecated:: 1.12.0 + Use instead `.param.values()` or `.param['param']` + """ + pdict = self_.objects(instance='existing') + if parameter_name is None: + return pdict + else: + return pdict[parameter_name]
+ + # Bothmethods + +
[docs] def update(self_, *args, **kwargs): + """ + For the given dictionary or iterable or set of param=value + keyword arguments, sets the corresponding parameter of this + object or class to the given value. + + May also be used as a context manager to temporarily set and + then reset parameter values. + """ + restore = self_._update(*args, **kwargs) + return _ParametersRestorer(parameters=self_, restore=restore)
+ + def _update(self_, *args, **kwargs): + BATCH_WATCH = self_._BATCH_WATCH + self_._BATCH_WATCH = True + self_or_cls = self_.self_or_cls + if args: + if len(args) == 1 and not kwargs: + kwargs = args[0] + else: + self_._BATCH_WATCH = False + raise ValueError( + f"{self_.cls.__name__}.param.update accepts *either* an iterable " + "or key=value pairs, not both." + ) + + trigger_params = [ + k for k in kwargs + if k in self_ and hasattr(self_[k], '_autotrigger_value') + ] + + for tp in trigger_params: + self_[tp]._mode = 'set' + + values = self_.values() + restore = {k: values[k] for k, v in kwargs.items() if k in values} + + for (k, v) in kwargs.items(): + if k not in self_: + self_._BATCH_WATCH = False + raise ValueError(f"{k!r} is not a parameter of {self_.cls.__name__}") + try: + setattr(self_or_cls, k, v) + except: + self_._BATCH_WATCH = False + raise + + self_._BATCH_WATCH = BATCH_WATCH + if not BATCH_WATCH: + self_._batch_call_watchers() + + for tp in trigger_params: + p = self_[tp] + p._mode = 'reset' + setattr(self_or_cls, tp, p._autotrigger_reset_value) + p._mode = 'set-reset' + return restore + + # PARAM3_DEPRECATION +
[docs] @_deprecated(extra_msg="Use instead `.param.update`") + def set_param(self_, *args,**kwargs): + """ + For each param=value keyword argument, sets the corresponding + parameter of this object or class to the given value. + + For backwards compatibility, also accepts + set_param("param",value) for a single parameter value using + positional arguments, but the keyword interface is preferred + because it is more compact and can set multiple values. + + .. deprecated:: 1.12.0 + Use instead `.param.update` + """ + self_or_cls = self_.self_or_cls + if args: + if len(args) == 2 and not args[0] in kwargs and not kwargs: + kwargs[args[0]] = args[1] + else: + raise ValueError("Invalid positional arguments for %s.set_param" % + (self_or_cls.name)) + return self_.update(kwargs)
+ +
[docs] def objects(self_, instance=True): + """ + Returns the Parameters of this instance or class + + If instance=True and called on a Parameterized instance it + will create instance parameters for all Parameters defined on + the class. To force class parameters to be returned use + instance=False. Since classes avoid creating instance + parameters unless necessary you may also request only existing + instance parameters to be returned by setting + instance='existing'. + """ + if self_.self is not None and not self_.self._param__private.initialized and instance is True: + warnings.warn( + 'Looking up instance Parameter objects (`.param.objects()`) until ' + 'the Parameterized instance has been fully initialized is deprecated and will raise an error in a future version. ' + 'Ensure you have called `super().__init__(**params)` in your Parameterized ' + 'constructor before trying to access instance Parameter objects, or ' + 'looking up the class Parameter objects with `.param.objects(instance=False)` ' + 'may be enough for your use case.', + category=_ParamFutureWarning, + stacklevel=2, + ) + + cls = self_.cls + # We cache the parameters because this method is called often, + # and parameters are rarely added (and cannot be deleted) + pdict = cls._param__private.params + if not pdict: + paramdict = {} + for class_ in classlist(cls): + for name, val in class_.__dict__.items(): + if isinstance(val, Parameter): + paramdict[name] = val + + # We only want the cache to be visible to the cls on which + # params() is called, so we mangle the name ourselves at + # runtime (if we were to mangle it now, it would be + # _Parameterized.__params for all classes). + # cls._param__private.params[f'_{cls.__name__}__params'] = paramdict + cls._param__private.params = paramdict + pdict = paramdict + + if instance and self_.self is not None: + if instance == 'existing': + if getattr(self_.self._param__private, 'initialized', False) and self_.self._param__private.params: + return dict(pdict, **self_.self._param__private.params) + return pdict + else: + return {k: self_.self.param[k] for k in pdict} + return pdict
+ +
[docs] def trigger(self_, *param_names): + """ + Trigger watchers for the given set of parameter names. Watchers + will be triggered whether or not the parameter values have + actually changed. As a special case, the value will actually be + changed for a Parameter of type Event, setting it to True so + that it is clear which Event parameter has been triggered. + """ + if self_.self is not None and not self_.self._param__private.initialized: + warnings.warn( + 'Triggering watchers on a partially initialized Parameterized instance ' + 'is deprecated and will raise an error in a future version. ' + 'Ensure you have called super().__init__(**params) in ' + 'the Parameterized instance constructor before trying to set up a watcher.', + category=_ParamFutureWarning, + stacklevel=2, + ) + + trigger_params = [p for p in self_ + if hasattr(self_[p], '_autotrigger_value')] + triggers = {p:self_[p]._autotrigger_value + for p in trigger_params if p in param_names} + + events = self_._events + watchers = self_._state_watchers + self_._events = [] + self_._state_watchers = [] + param_values = self_.values() + params = {name: param_values[name] for name in param_names} + self_._TRIGGER = True + self_.update(dict(params, **triggers)) + self_._TRIGGER = False + self_._events += events + self_._state_watchers += watchers
+ + def _update_event_type(self_, watcher, event, triggered): + """ + Returns an updated Event object with the type field set appropriately. + """ + if triggered: + event_type = 'triggered' + else: + event_type = 'changed' if watcher.onlychanged else 'set' + return Event(what=event.what, name=event.name, obj=event.obj, cls=event.cls, + old=event.old, new=event.new, type=event_type) + + def _execute_watcher(self, watcher, events): + if watcher.mode == 'args': + args, kwargs = events, {} + else: + args, kwargs = (), {event.name: event.new for event in events} + + if iscoroutinefunction(watcher.fn): + if async_executor is None: + raise RuntimeError("Could not execute %s coroutine function. " + "Please register a asynchronous executor on " + "param.parameterized.async_executor, which " + "schedules the function on an event loop." % + watcher.fn) + async_executor(partial(watcher.fn, *args, **kwargs)) + else: + watcher.fn(*args, **kwargs) + + def _call_watcher(self_, watcher, event): + """ + Invoke the given watcher appropriately given an Event object. + """ + if self_._TRIGGER: + pass + elif watcher.onlychanged and (not self_._changed(event)): + return + + if self_._BATCH_WATCH: + self_._events.append(event) + if not any(watcher is w for w in self_._state_watchers): + self_._state_watchers.append(watcher) + else: + event = self_._update_event_type(watcher, event, self_._TRIGGER) + with _batch_call_watchers(self_.self_or_cls, enable=watcher.queued, run=False): + self_._execute_watcher(watcher, (event,)) + + def _batch_call_watchers(self_): + """ + Batch call a set of watchers based on the parameter value + settings in kwargs using the queued Event and watcher objects. + """ + while self_._events: + event_dict = OrderedDict([((event.name, event.what), event) + for event in self_._events]) + watchers = self_._state_watchers[:] + self_._events = [] + self_._state_watchers = [] + + for watcher in sorted(watchers, key=lambda w: w.precedence): + events = [self_._update_event_type(watcher, event_dict[(name, watcher.what)], + self_._TRIGGER) + for name in watcher.parameter_names + if (name, watcher.what) in event_dict] + with _batch_call_watchers(self_.self_or_cls, enable=watcher.queued, run=False): + self_._execute_watcher(watcher, events) + +
[docs] def set_dynamic_time_fn(self_,time_fn,sublistattr=None): + """ + Set time_fn for all Dynamic Parameters of this class or + instance object that are currently being dynamically + generated. + + Additionally, sets _Dynamic_time_fn=time_fn on this class or + instance object, so that any future changes to Dynamic + Parmeters can inherit time_fn (e.g. if a Number is changed + from a float to a number generator, the number generator will + inherit time_fn). + + If specified, sublistattr is the name of an attribute of this + class or instance that contains an iterable collection of + subobjects on which set_dynamic_time_fn should be called. If + the attribute sublistattr is present on any of the subobjects, + set_dynamic_time_fn() will be called for those, too. + """ + self_or_cls = self_.self_or_cls + self_or_cls._Dynamic_time_fn = time_fn + + if isinstance(self_or_cls,type): + a = (None,self_or_cls) + else: + a = (self_or_cls,) + + for n,p in self_or_cls.param.objects('existing').items(): + if hasattr(p, '_value_is_dynamic'): + if p._value_is_dynamic(*a): + g = self_or_cls.param.get_value_generator(n) + g._Dynamic_time_fn = time_fn + + if sublistattr: + try: + sublist = getattr(self_or_cls,sublistattr) + except AttributeError: + sublist = [] + + for obj in sublist: + obj.param.set_dynamic_time_fn(time_fn,sublistattr)
+ +
[docs] def serialize_parameters(self_, subset=None, mode='json'): + self_or_cls = self_.self_or_cls + if mode not in Parameter._serializers: + raise ValueError(f'Mode {mode!r} not in available serialization formats {list(Parameter._serializers.keys())!r}') + serializer = Parameter._serializers[mode] + return serializer.serialize_parameters(self_or_cls, subset=subset)
+ +
[docs] def serialize_value(self_, pname, mode='json'): + self_or_cls = self_.self_or_cls + if mode not in Parameter._serializers: + raise ValueError(f'Mode {mode!r} not in available serialization formats {list(Parameter._serializers.keys())!r}') + serializer = Parameter._serializers[mode] + return serializer.serialize_parameter_value(self_or_cls, pname)
+ +
[docs] def deserialize_parameters(self_, serialization, subset=None, mode='json'): + self_or_cls = self_.self_or_cls + serializer = Parameter._serializers[mode] + return serializer.deserialize_parameters(self_or_cls, serialization, subset=subset)
+ +
[docs] def deserialize_value(self_, pname, value, mode='json'): + self_or_cls = self_.self_or_cls + if mode not in Parameter._serializers: + raise ValueError(f'Mode {mode!r} not in available serialization formats {list(Parameter._serializers.keys())!r}') + serializer = Parameter._serializers[mode] + return serializer.deserialize_parameter_value(self_or_cls, pname, value)
+ +
[docs] def schema(self_, safe=False, subset=None, mode='json'): + """ + Returns a schema for the parameters on this Parameterized object. + """ + self_or_cls = self_.self_or_cls + if mode not in Parameter._serializers: + raise ValueError(f'Mode {mode!r} not in available serialization formats {list(Parameter._serializers.keys())!r}') + serializer = Parameter._serializers[mode] + return serializer.schema(self_or_cls, safe=safe, subset=subset)
+ + # PARAM3_DEPRECATION + # same as values() but returns list, not dict +
[docs] @_deprecated(extra_msg=""" + Use `.param.values().items()` instead (or `.param.values()` for the + common case of `dict(....param.get_param_values())`) + """) + def get_param_values(self_, onlychanged=False): + """ + Return a list of name,value pairs for all Parameters of this + object. + + When called on an instance with onlychanged set to True, will + only return values that are not equal to the default value + (onlychanged has no effect when called on a class). + + .. deprecated:: 1.12.0 + Use `.param.values().items()` instead (or `.param.values()` for the + common case of `dict(....param.get_param_values())`) + """ + vals = self_.values(onlychanged) + return [(k, v) for k, v in vals.items()]
+ +
[docs] def values(self_, onlychanged=False): + """ + Return a dictionary of name,value pairs for the Parameters of this + object. + + When called on an instance with onlychanged set to True, will + only return values that are not equal to the default value + (onlychanged has no effect when called on a class). + """ + self_or_cls = self_.self_or_cls + vals = [] + for name, val in self_or_cls.param.objects('existing').items(): + value = self_or_cls.param.get_value_generator(name) + if name == 'name' and onlychanged and _is_auto_name(self_.cls.__name__, value): + continue + if not onlychanged or not Comparator.is_equal(value, val.default): + vals.append((name, value)) + + vals.sort(key=itemgetter(0)) + return dict(vals)
+ +
[docs] def force_new_dynamic_value(self_, name): # pylint: disable-msg=E0213 + """ + Force a new value to be generated for the dynamic attribute + name, and return it. + + If name is not dynamic, its current value is returned + (i.e. equivalent to getattr(name). + """ + cls_or_slf = self_.self_or_cls + param_obj = cls_or_slf.param.objects('existing').get(name) + + if not param_obj: + return getattr(cls_or_slf, name) + + cls, slf = None, None + if isinstance(cls_or_slf,type): + cls = cls_or_slf + else: + slf = cls_or_slf + + if not hasattr(param_obj,'_force'): + return param_obj.__get__(slf, cls) + else: + return param_obj._force(slf, cls)
+ +
[docs] def get_value_generator(self_,name): # pylint: disable-msg=E0213 + """ + Return the value or value-generating object of the named + attribute. + + For most parameters, this is simply the parameter's value + (i.e. the same as getattr()), but Dynamic parameters have + their value-generating object returned. + """ + cls_or_slf = self_.self_or_cls + param_obj = cls_or_slf.param.objects('existing').get(name) + + if not param_obj: + value = getattr(cls_or_slf,name) + + # CompositeParameter detected by being a Parameter and having 'attribs' + elif hasattr(param_obj,'attribs'): + value = [cls_or_slf.param.get_value_generator(a) for a in param_obj.attribs] + + # not a Dynamic Parameter + elif not hasattr(param_obj,'_value_is_dynamic'): + value = getattr(cls_or_slf,name) + + # Dynamic Parameter... + else: + # TODO: is this always an instance? + if isinstance(cls_or_slf, Parameterized) and name in cls_or_slf._param__private.values: + # dealing with object and it's been set on this object + value = cls_or_slf._param__private.values[name] + else: + # dealing with class or isn't set on the object + value = param_obj.default + + return value
+ +
[docs] def inspect_value(self_,name): # pylint: disable-msg=E0213 + """ + Return the current value of the named attribute without modifying it. + + Same as getattr() except for Dynamic parameters, which have their + last generated value returned. + """ + cls_or_slf = self_.self_or_cls + param_obj = cls_or_slf.param.objects('existing').get(name) + + if not param_obj: + value = getattr(cls_or_slf,name) + elif hasattr(param_obj,'attribs'): + value = [cls_or_slf.param.inspect_value(a) for a in param_obj.attribs] + elif not hasattr(param_obj,'_inspect'): + value = getattr(cls_or_slf,name) + else: + if isinstance(cls_or_slf,type): + value = param_obj._inspect(None,cls_or_slf) + else: + value = param_obj._inspect(cls_or_slf,None) + + return value
+ +
[docs] def method_dependencies(self_, name, intermediate=False): + """ + Given the name of a method, returns a PInfo object for each dependency + of this method. See help(PInfo) for the contents of these objects. + + By default intermediate dependencies on sub-objects are not + returned as these are primarily useful for internal use to + determine when a sub-object dependency has to be updated. + """ + method = getattr(self_.self_or_cls, name) + minfo = MInfo(cls=self_.cls, inst=self_.self, name=name, + method=method) + deps, dynamic = _params_depended_on( + minfo, dynamic=False, intermediate=intermediate) + if self_.self is None: + return deps + return _resolve_mcs_deps( + self_.self, deps, dynamic, intermediate=intermediate)
+ + # PARAM3_DEPRECATION +
[docs] @_deprecated(extra_msg='Use instead `.param.method_dependencies`') + def params_depended_on(self_, *args, **kwargs): + """ + Given the name of a method, returns a PInfo object for each dependency + of this method. See help(PInfo) for the contents of these objects. + + By default intermediate dependencies on sub-objects are not + returned as these are primarily useful for internal use to + determine when a sub-object dependency has to be updated. + + .. deprecated: 2.0.0 + Use instead `.param.method_dependencies` + """ + return self_.method_dependencies(*args, **kwargs)
+ +
[docs] def outputs(self_): + """ + Returns a mapping between any declared outputs and a tuple + of the declared Parameter type, the output method, and the + index into the output if multiple outputs are returned. + """ + outputs = {} + for cls in classlist(self_.cls): + for name in dir(cls): + if name == '_param_watchers': + continue + method = getattr(self_.self_or_cls, name) + dinfo = getattr(method, '_dinfo', {}) + if 'outputs' not in dinfo: + continue + for override, otype, idx in dinfo['outputs']: + if override is not None: + name = override + outputs[name] = (otype, method, idx) + return outputs
+ + def _spec_to_obj(self_, spec, dynamic=True, intermediate=True): + """ + Resolves a dependency specification into lists of explicit + parameter dependencies and dynamic dependencies. + + Dynamic dependencies are specifications to be resolved when + the sub-object whose parameters are being depended on is + defined. + + During class creation dynamic=False which means sub-object + dependencies are not resolved. At instance creation and + whenever a sub-object is set on an object this method will be + invoked to determine whether the dependency is available. + + For sub-object dependencies we also return dependencies for + every part of the path, e.g. for a dependency specification + like "a.b.c" we return dependencies for sub-object "a" and the + sub-sub-object "b" in addition to the dependency on the actual + parameter "c" on object "b". This is to ensure that if a + sub-object is swapped out we are notified and can update the + dynamic dependency to the new object. Even if a sub-object + dependency can only partially resolved, e.g. if object "a" + does not yet have a sub-object "b" we must watch for changes + to "b" on sub-object "a" in case such a subobject is put in "b". + """ + if isinstance(spec, Parameter): + inst = spec.owner if isinstance(spec.owner, Parameterized) else None + cls = spec.owner if inst is None else type(inst) + info = PInfo(inst=inst, cls=cls, name=spec.name, + pobj=spec, what='value') + return [] if intermediate == 'only' else [info], [] + + obj, attr, what = _parse_dependency_spec(spec) + if obj is None: + src = self_.self_or_cls + elif not dynamic: + return [], [DInfo(spec=spec)] + else: + if not hasattr(self_.self_or_cls, obj.split('.')[1]): + raise AttributeError( + f'Dependency {obj[1:]!r} could not be resolved, {self_.self_or_cls} ' + f'has no parameter or attribute {obj.split(".")[1]!r}. Ensure ' + 'the object being depended on is declared before calling the ' + 'Parameterized constructor.' + ) + + src = _getattrr(self_.self_or_cls, obj[1::], None) + if src is None: + path = obj[1:].split('.') + deps = [] + # Attempt to partially resolve subobject path to ensure + # that if a subobject is later updated making the full + # subobject path available we have to be notified and + # set up watchers + if len(path) >= 1 and intermediate: + sub_src = None + subpath = path + while sub_src is None and subpath: + subpath = subpath[:-1] + sub_src = _getattrr(self_.self_or_cls, '.'.join(subpath), None) + if subpath: + subdeps, _ = self_._spec_to_obj( + '.'.join(path[:len(subpath)+1]), dynamic, intermediate) + deps += subdeps + return deps, [] if intermediate == 'only' else [DInfo(spec=spec)] + + cls, inst = (src, None) if isinstance(src, type) else (type(src), src) + if attr == 'param': + deps, dynamic_deps = self_._spec_to_obj(obj[1:], dynamic, intermediate) + for p in src.param: + param_deps, param_dynamic_deps = src.param._spec_to_obj(p, dynamic, intermediate) + deps += param_deps + dynamic_deps += param_dynamic_deps + return deps, dynamic_deps + elif attr in src.param: + info = PInfo(inst=inst, cls=cls, name=attr, + pobj=src.param[attr], what=what) + elif hasattr(src, attr): + attr_obj = getattr(src, attr) + if isinstance(attr_obj, Parameterized): + return [], [] + elif isinstance(attr_obj, (FunctionType, MethodType)): + info = MInfo(inst=inst, cls=cls, name=attr, + method=attr_obj) + else: + raise AttributeError(f"Attribute {attr!r} could not be resolved on {src}.") + elif getattr(src, "abstract", None): + return [], [] if intermediate == 'only' else [DInfo(spec=spec)] + else: + raise AttributeError(f"Attribute {attr!r} could not be resolved on {src}.") + + if obj is None or not intermediate: + return [info], [] + deps, dynamic_deps = self_._spec_to_obj(obj[1:], dynamic, intermediate) + if intermediate != 'only': + deps.append(info) + return deps, dynamic_deps + + def _register_watcher(self_, action, watcher, what='value'): + if self_.self is not None and not self_.self._param__private.initialized: + warnings.warn( + '(Un)registering a watcher on a partially initialized Parameterized instance ' + 'is deprecated and will raise an error in a future version. Ensure ' + 'you have called super().__init__(**) in the Parameterized instance ' + 'constructor before trying to set up a watcher.', + category=_ParamFutureWarning, + stacklevel=4, + ) + + parameter_names = watcher.parameter_names + for parameter_name in parameter_names: + if parameter_name not in self_.cls.param: + raise ValueError("{} parameter was not found in list of " + "parameters of class {}".format(parameter_name, self_.cls.__name__)) + + if self_.self is not None and what == "value": + watchers = self_.self._param__private.watchers + if parameter_name not in watchers: + watchers[parameter_name] = {} + if what not in watchers[parameter_name]: + watchers[parameter_name][what] = [] + getattr(watchers[parameter_name][what], action)(watcher) + else: + watchers = self_[parameter_name].watchers + if what not in watchers: + watchers[what] = [] + getattr(watchers[what], action)(watcher) + +
[docs] def watch(self_, fn, parameter_names, what='value', onlychanged=True, queued=False, precedence=0): + """ + Register the given callback function `fn` to be invoked for + events on the indicated parameters. + + `what`: What to watch on each parameter; either the value (by + default) or else the indicated slot (e.g. 'constant'). + + `onlychanged`: By default, only invokes the function when the + watched item changes, but if `onlychanged=False` also invokes + it when the `what` item is set to its current value again. + + `queued`: By default, additional watcher events generated + inside the callback fn are dispatched immediately, effectively + doing depth-first processing of Watcher events. However, in + certain scenarios, it is helpful to wait to dispatch such + downstream events until all events that triggered this watcher + have been processed. In such cases setting `queued=True` on + this Watcher will queue up new downstream events generated + during `fn` until `fn` completes and all other watchers + invoked by that same event have finished executing), + effectively doing breadth-first processing of Watcher events. + + `precedence`: Declares a precedence level for the Watcher that + determines the priority with which the callback is executed. + Lower precedence levels are executed earlier. Negative + precedences are reserved for internal Watchers, i.e. those + set up by param.depends. + + When the `fn` is called, it will be provided the relevant + Event objects as positional arguments, which allows it to + determine which of the possible triggering events occurred. + + Returns a Watcher object. + + See help(Watcher) and help(Event) for the contents of those objects. + """ + if precedence < 0: + raise ValueError("User-defined watch callbacks must declare " + "a positive precedence. Negative precedences " + "are reserved for internal Watchers.") + return self_._watch(fn, parameter_names, what, onlychanged, queued, precedence)
+ + def _watch(self_, fn, parameter_names, what='value', onlychanged=True, queued=False, precedence=-1): + parameter_names = tuple(parameter_names) if isinstance(parameter_names, list) else (parameter_names,) + watcher = Watcher(inst=self_.self, cls=self_.cls, fn=fn, mode='args', + onlychanged=onlychanged, parameter_names=parameter_names, + what=what, queued=queued, precedence=precedence) + self_._register_watcher('append', watcher, what) + return watcher + +
[docs] def unwatch(self_, watcher): + """ + Remove the given Watcher object (from `watch` or `watch_values`) from this object's list. + """ + try: + self_._register_watcher('remove', watcher, what=watcher.what) + except Exception: + self_.warning(f'No such watcher {str(watcher)} to remove.')
+ +
[docs] def watch_values(self_, fn, parameter_names, what='value', onlychanged=True, queued=False, precedence=0): + """ + Easier-to-use version of `watch` specific to watching for changes in parameter values. + + Only allows `what` to be 'value', and invokes the callback `fn` using keyword + arguments <param_name>=<new_value> rather than with a list of Event objects. + """ + if precedence < 0: + raise ValueError("User-defined watch callbacks must declare " + "a positive precedence. Negative precedences " + "are reserved for internal Watchers.") + assert what == 'value' + if isinstance(parameter_names, list): + parameter_names = tuple(parameter_names) + else: + parameter_names = (parameter_names,) + watcher = Watcher(inst=self_.self, cls=self_.cls, fn=fn, + mode='kwargs', onlychanged=onlychanged, + parameter_names=parameter_names, what=what, + queued=queued, precedence=precedence) + self_._register_watcher('append', watcher, what) + return watcher
+ + # Instance methods + + # PARAM3_DEPRECATION +
[docs] @_deprecated(extra_msg="Use instead `{k:v.default for k,v in p.param.objects().items()}`") + def defaults(self_): + """ + Return {parameter_name:parameter.default} for all non-constant + Parameters. + + Note that a Parameter for which instantiate==True has its default + instantiated. + + .. deprecated:: 1.12.0 + Use instead `{k:v.default for k,v in p.param.objects().items()}` + """ + self = self_.self + d = {} + for param_name, param in self.param.objects('existing').items(): + if param.constant: + pass + if param.instantiate: + self.param._instantiate_param(param, dict_=d, key=param_name) + d[param_name] = param.default + return d
+ + # Designed to avoid any processing unless the print + # level is high enough, though not all callers of message(), + # verbose(), debug(), etc are taking advantage of this. + def __db_print(self_,level,msg,*args,**kw): + """ + Calls the logger returned by the get_logger() function, + prepending the result of calling dbprint_prefix() (if any). + + See python's logging module for details. + """ + self_or_cls = self_.self_or_cls + if get_logger(name=self_or_cls.name).isEnabledFor(level): + + if dbprint_prefix and callable(dbprint_prefix): + msg = dbprint_prefix() + ": " + msg # pylint: disable-msg=E1102 + + get_logger(name=self_or_cls.name).log(level, msg, *args, **kw) + + # PARAM3_DEPRECATION +
[docs] @_deprecated(extra_msg="""Use instead `for k,v in p.param.objects().items(): print(f"{p.__class__.name}.{k}={repr(v.default)}")`""") + def print_param_values(self_): + """Print the values of all this object's Parameters. + + .. deprecated:: 1.12.0 + Use instead `for k,v in p.param.objects().items(): print(f"{p.__class__.name}.{k}={repr(v.default)}")` + """ + self = self_.self + for name, val in self.param.values().items(): + print(f'{self.name}.{name} = {val}')
+ +
[docs] def warning(self_, msg,*args,**kw): + """ + Print msg merged with args as a warning, unless module variable + warnings_as_exceptions is True, then raise an Exception + containing the arguments. + + See Python's logging module for details of message formatting. + """ + self_.log(WARNING, msg, *args, **kw)
+ + # PARAM3_DEPRECATION +
[docs] @_deprecated(extra_msg="Use instead `.param.log(param.MESSAGE, ...)`") + def message(self_,msg,*args,**kw): + """ + Print msg merged with args as a message. + + See Python's logging module for details of message formatting. + + .. deprecated:: 1.12.0 + Use instead `.param.log(param.MESSAGE, ...)` + """ + self_.__db_print(INFO,msg,*args,**kw)
+ + # PARAM3_DEPRECATION +
[docs] @_deprecated(extra_msg="Use instead `.param.log(param.VERBOSE, ...)`") + def verbose(self_,msg,*args,**kw): + """ + Print msg merged with args as a verbose message. + + See Python's logging module for details of message formatting. + + .. deprecated:: 1.12.0 + Use instead `.param.log(param.VERBOSE, ...)` + """ + self_.__db_print(VERBOSE,msg,*args,**kw)
+ + # PARAM3_DEPRECATION +
[docs] @_deprecated(extra_msg="Use instead `.param.log(param.DEBUG, ...)`") + def debug(self_,msg,*args,**kw): + """ + Print msg merged with args as a debugging statement. + + See Python's logging module for details of message formatting. + + .. deprecated:: 1.12.0 + Use instead `.param.log(param.DEBUG, ...)` + """ + self_.__db_print(DEBUG,msg,*args,**kw)
+ +
[docs] def log(self_, level, msg, *args, **kw): + """ + Print msg merged with args as a message at the indicated logging level. + + Logging levels include those provided by the Python logging module + plus VERBOSE, either obtained directly from the logging module like + `logging.INFO`, or from parameterized like `param.parameterized.INFO`. + + Supported logging levels include (in order of severity) + DEBUG, VERBOSE, INFO, WARNING, ERROR, CRITICAL + + See Python's logging module for details of message formatting. + """ + if level is WARNING: + if warnings_as_exceptions: + raise Exception("Warning: " + msg % args) + else: + global warning_count + warning_count+=1 + self_.__db_print(level, msg, *args, **kw)
+ + # Note that there's no state_push method on the class, so + # dynamic parameters set on a class can't have state saved. This + # is because, to do this, state_push() would need to be a + # @bothmethod, but that complicates inheritance in cases where we + # already have a state_push() method. + # (isinstance(g,Parameterized) below is used to exclude classes.) + + def _state_push(self_): + """ + Save this instance's state. + + For Parameterized instances, this includes the state of + dynamically generated values. + + Subclasses that maintain short-term state should additionally + save and restore that state using state_push() and + state_pop(). + + Generally, this method is used by operations that need to test + something without permanently altering the objects' state. + """ + self = self_.self_or_cls + if not isinstance(self, Parameterized): + raise NotImplementedError('_state_push is not implemented at the class level') + for pname, p in self.param.objects('existing').items(): + g = self.param.get_value_generator(pname) + if hasattr(g,'_Dynamic_last'): + g._saved_Dynamic_last.append(g._Dynamic_last) + g._saved_Dynamic_time.append(g._Dynamic_time) + # CB: not storing the time_fn: assuming that doesn't + # change. + elif hasattr(g,'state_push') and isinstance(g,Parameterized): + g.state_push() + + def _state_pop(self_): + """ + Restore the most recently saved state. + + See state_push() for more details. + """ + self = self_.self_or_cls + if not isinstance(self, Parameterized): + raise NotImplementedError('_state_pop is not implemented at the class level') + for pname, p in self.param.objects('existing').items(): + g = self.param.get_value_generator(pname) + if hasattr(g,'_Dynamic_last'): + g._Dynamic_last = g._saved_Dynamic_last.pop() + g._Dynamic_time = g._saved_Dynamic_time.pop() + elif hasattr(g,'state_pop') and isinstance(g,Parameterized): + g.state_pop() + +
[docs] def pprint(self_, imports=None, prefix=" ", unknown_value='<?>', + qualify=False, separator=""): + """ + (Experimental) Pretty printed representation that may be + evaluated with eval. See pprint() function for more details. + """ + self = self_.self_or_cls + if not isinstance(self, Parameterized): + raise NotImplementedError('pprint is not implemented at the class level') + # Wrapping the staticmethod _pprint with partial to pass `self` as the `_recursive_repr` + # decorator expects `self`` to be the pprinted object (not `self_`). + return partial(self_._pprint, self, imports=imports, prefix=prefix, + unknown_value=unknown_value, qualify=qualify, separator=separator)()
+ + @staticmethod + @_recursive_repr() + def _pprint(self, imports=None, prefix=" ", unknown_value='<?>', + qualify=False, separator=""): + if imports is None: + imports = [] # would have been simpler to use a set from the start + imports[:] = list(set(imports)) + + # Generate import statement + mod = self.__module__ + bits = mod.split('.') + imports.append("import %s"%mod) + imports.append("import %s"%bits[0]) + + changed_params = self.param.values(onlychanged=script_repr_suppress_defaults) + values = self.param.values() + spec = getfullargspec(type(self).__init__) + if 'self' not in spec.args or spec.args[0] != 'self': + raise KeyError(f"'{type(self).__name__}.__init__.__signature__' must contain 'self' as its first Parameter.") + args = spec.args[1:] + + if spec.defaults is not None: + posargs = spec.args[:-len(spec.defaults)] + kwargs = dict(zip(spec.args[-len(spec.defaults):], spec.defaults)) + else: + posargs, kwargs = args, [] + + parameters = self.param.objects('existing') + ordering = sorted( + sorted(changed_params), # alphanumeric tie-breaker + key=lambda k: (- float('inf') # No precedence is lowest possible precendence + if parameters[k].precedence is None else + parameters[k].precedence)) + + arglist, keywords, processed = [], [], [] + for k in args + ordering: + if k in processed: continue + + # Suppresses automatically generated names. + if k == 'name' and (values[k] is not None + and re.match('^'+self.__class__.__name__+'[0-9]+$', values[k])): + continue + + value = pprint(values[k], imports, prefix=prefix,settings=[], + unknown_value=unknown_value, + qualify=qualify) if k in values else None + + if value is None: + if unknown_value is False: + raise Exception(f"{self.name}: unknown value of {k!r}") + elif unknown_value is None: + # i.e. suppress repr + continue + else: + value = unknown_value + + # Explicit kwarg (unchanged, known value) + if (k in kwargs) and (k in values) and kwargs[k] == values[k]: continue + + if k in posargs: + # value will be unknown_value unless k is a parameter + arglist.append(value) + elif (k in kwargs or + (hasattr(spec, 'varkw') and (spec.varkw is not None)) or + (hasattr(spec, 'keywords') and (spec.keywords is not None))): + # Explicit modified keywords or parameters in + # precendence order (if **kwargs present) + keywords.append(f'{k}={value}') + + processed.append(k) + + qualifier = mod + '.' if qualify else '' + arguments = arglist + keywords + (['**%s' % spec.varargs] if spec.varargs else []) + return qualifier + '{}({})'.format(self.__class__.__name__, (','+separator+prefix).join(arguments)) + + +class ParameterizedMetaclass(type): + """ + The metaclass of Parameterized (and all its descendents). + + The metaclass overrides type.__setattr__ to allow us to set + Parameter values on classes without overwriting the attribute + descriptor. That is, for a Parameterized class of type X with a + Parameter y, the user can type X.y=3, which sets the default value + of Parameter y to be 3, rather than overwriting y with the + constant value 3 (and thereby losing all other info about that + Parameter, such as the doc string, bounds, etc.). + + The __init__ method is used when defining a Parameterized class, + usually when the module where that class is located is imported + for the first time. That is, the __init__ in this metaclass + initializes the *class* object, while the __init__ method defined + in each Parameterized class is called for each new instance of + that class. + + Additionally, a class can declare itself abstract by having an + attribute __abstract set to True. The 'abstract' attribute can be + used to find out if a class is abstract or not. + """ + def __init__(mcs, name, bases, dict_): + """ + Initialize the class object (not an instance of the class, but + the class itself). + + Initializes all the Parameters by looking up appropriate + default values (see __param_inheritance()) and setting + attrib_names (see _set_names()). + """ + type.__init__(mcs, name, bases, dict_) + + # Compute which parameters explicitly do not support references + # This can be removed when Parameter.allow_refs=True by default. + explicit_no_refs = set() + for base in bases: + if issubclass(base, Parameterized): + explicit_no_refs |= set(base._param__private.explicit_no_refs) + + _param__private = _ClassPrivate(explicit_no_refs=list(explicit_no_refs)) + mcs._param__private = _param__private + mcs.__set_name(name, dict_) + mcs._param__parameters = Parameters(mcs) + + # All objects (with their names) of type Parameter that are + # defined in this class + parameters = [(n, o) for (n, o) in dict_.items() + if isinstance(o, Parameter)] + + for param_name,param in parameters: + mcs._initialize_parameter(param_name, param) + + # retrieve depends info from methods and store more conveniently + dependers = [(n, m, m._dinfo) for (n, m) in dict_.items() + if hasattr(m, '_dinfo')] + + # Resolve dependencies of current class + _watch = [] + for name, method, dinfo in dependers: + watch = dinfo.get('watch', False) + on_init = dinfo.get('on_init', False) + minfo = MInfo(cls=mcs, inst=None, name=name, + method=method) + deps, dynamic_deps = _params_depended_on(minfo, dynamic=False) + if watch: + _watch.append((name, watch == 'queued', on_init, deps, dynamic_deps)) + + # Resolve dependencies in class hierarchy + _inherited = [] + for cls in classlist(mcs)[:-1][::-1]: + if not hasattr(cls, '_param__parameters'): + continue + for dep in cls.param._depends['watch']: + method = getattr(mcs, dep[0], None) + dinfo = getattr(method, '_dinfo', {'watch': False}) + if (not any(dep[0] == w[0] for w in _watch+_inherited) + and dinfo.get('watch')): + _inherited.append(dep) + + mcs.param._depends = {'watch': _inherited+_watch} + + if docstring_signature: + mcs.__class_docstring() + + def __set_name(mcs, name, dict_): + """ + Give Parameterized classes a useful 'name' attribute that is by + default the class name, unless a class in the hierarchy has defined + a `name` String Parameter with a defined `default` value, in which case + that value is used to set the class name. + """ + name_param = dict_.get("name", None) + if name_param is not None: + if not type(name_param) is String: + raise TypeError( + f"Parameterized class {name!r} cannot override " + f"the 'name' Parameter with type {type(name_param)}. " + "Overriding 'name' is only allowed with a 'String' Parameter." + ) + if name_param.default: + mcs.name = name_param.default + mcs._param__private.renamed = True + else: + mcs.name = name + else: + classes = classlist(mcs)[::-1] + found_renamed = False + for c in classes: + if hasattr(c, '_param__private') and c._param__private.renamed: + found_renamed = True + break + if not found_renamed: + mcs.name = name + + def __class_docstring(mcs): + """ + Customize the class docstring with a Parameter table if + `docstring_describe_params` and the `param_pager` is available. + """ + if not docstring_describe_params or not param_pager: + return + class_docstr = mcs.__doc__ if mcs.__doc__ else '' + description = param_pager(mcs) + mcs.__doc__ = class_docstr + '\n' + description + + def _initialize_parameter(mcs, param_name, param): + # A Parameter has no way to find out the name a + # Parameterized class has for it + param._set_names(param_name) + mcs.__param_inheritance(param_name, param) + + # Should use the official Python 2.6+ abstract base classes; see + # https://github.com/holoviz/param/issues/84 + def __is_abstract(mcs): + """ + Return True if the class has an attribute __abstract set to True. + Subclasses will return False unless they themselves have + __abstract set to true. This mechanism allows a class to + declare itself to be abstract (e.g. to avoid it being offered + as an option in a GUI), without the "abstract" property being + inherited by its subclasses (at least one of which is + presumably not abstract). + """ + # Can't just do ".__abstract", because that is mangled to + # _ParameterizedMetaclass__abstract before running, but + # the actual class object will have an attribute + # _ClassName__abstract. So, we have to mangle it ourselves at + # runtime. Mangling follows description in + # https://docs.python.org/2/tutorial/classes.html#private-variables-and-class-local-references + try: + return getattr(mcs,'_%s__abstract'%mcs.__name__.lstrip("_")) + except AttributeError: + return False + + def __get_signature(mcs): + """ + For classes with a constructor signature that matches the default + Parameterized.__init__ signature (i.e. ``__init__(self, **params)``) + this method will generate a new signature that expands the + parameters. If the signature differs from the default the + custom signature is returned. + """ + if mcs._param__private.signature: + return mcs._param__private.signature + # allowed_signature must be the signature of Parameterized.__init__ + # Inspecting `mcs.__init__` instead of `mcs` to avoid a recursion error + if inspect.signature(mcs.__init__) != DEFAULT_SIGNATURE: + return None + processed_kws, keyword_groups = set(), [] + for cls in reversed(mcs.mro()): + keyword_group = [] + for k, v in sorted(cls.__dict__.items()): + if isinstance(v, Parameter) and k not in processed_kws and not v.readonly: + keyword_group.append(k) + processed_kws.add(k) + keyword_groups.append(keyword_group) + + keywords = [el for grp in reversed(keyword_groups) for el in grp] + mcs._param__private.signature = signature = inspect.Signature([ + inspect.Parameter(k, inspect.Parameter.KEYWORD_ONLY) + for k in keywords + ]) + return signature + + __signature__ = property(__get_signature) + + abstract = property(__is_abstract) + + def _get_param(mcs): + return mcs._param__parameters + + param = property(_get_param) + + def __setattr__(mcs, attribute_name, value): + """ + Implements 'self.attribute_name=value' in a way that also supports Parameters. + + If there is already a descriptor named attribute_name, and + that descriptor is a Parameter, and the new value is *not* a + Parameter, then call that Parameter's __set__ method with the + specified value. + + In all other cases set the attribute normally (i.e. overwrite + the descriptor). If the new value is a Parameter, once it has + been set we make sure that the value is inherited from + Parameterized superclasses as described in __param_inheritance(). + """ + # Find out if there's a Parameter called attribute_name as a + # class attribute of this class - if not, parameter is None. + parameter,owning_class = mcs.get_param_descriptor(attribute_name) + + if parameter and not isinstance(value,Parameter): + if owning_class != mcs: + parameter = copy.copy(parameter) + parameter.owner = mcs + type.__setattr__(mcs,attribute_name,parameter) + mcs.__dict__[attribute_name].__set__(None,value) + + else: + type.__setattr__(mcs,attribute_name,value) + + if isinstance(value,Parameter): + mcs.__param_inheritance(attribute_name,value) + + def __param_inheritance(mcs, param_name, param): + """ + Look for Parameter values in superclasses of this + Parameterized class. + + Ordinarily, when a Python object is instantiated, attributes + not given values in the constructor will inherit the value + given in the object's class, or in its superclasses. For + Parameters owned by Parameterized classes, we have implemented + an additional level of default lookup, should this ordinary + lookup return only `Undefined`. + + In such a case, i.e. when no non-`Undefined` value was found for a + Parameter by the usual inheritance mechanisms, we explicitly + look for Parameters with the same name in superclasses of this + Parameterized class, and use the first such value that we + find. + + The goal is to be able to set the default value (or other + slots) of a Parameter within a Parameterized class, just as we + can set values for non-Parameter objects in Parameterized + classes, and have the values inherited through the + Parameterized hierarchy as usual. + + Note that instantiate is handled differently: if there is a + parameter with the same name in one of the superclasses with + instantiate set to True, this parameter will inherit + instantiate=True. + """ + # get all relevant slots (i.e. slots defined in all + # superclasses of this parameter) + p_type = type(param) + slots = dict.fromkeys(p_type._all_slots_) + + # note for some eventual future: python 3.6+ descriptors grew + # __set_name__, which could replace this and _set_names + setattr(param, 'owner', mcs) + del slots['owner'] + + # backwards compatibility (see Composite parameter) + if 'objtype' in slots: + setattr(param, 'objtype', mcs) + del slots['objtype'] + + supers = classlist(mcs)[::-1] + + # Explicitly inherit instantiate from super class and + # check if type has changed to a more specific or different + # Parameter type, requiring extra validation + type_change = False + for superclass in supers: + super_param = superclass.__dict__.get(param_name) + if not isinstance(super_param, Parameter): + continue + if super_param.instantiate is True: + param.instantiate = True + super_type = type(super_param) + if not issubclass(super_type, p_type): + type_change = True + del slots['instantiate'] + + callables, slot_values = {}, {} + slot_overridden = False + for slot in slots.keys(): + # Search up the hierarchy until param.slot (which has to + # be obtained using getattr(param,slot)) is not Undefined, + # is a new value (using identity) or we run out of classes + # to search. + for scls in supers: + # Class may not define parameter or slot might not be + # there because could be a more general type of Parameter + new_param = scls.__dict__.get(param_name) + if new_param is None or not hasattr(new_param, slot): + continue + + new_value = getattr(new_param, slot) + old_value = slot_values.get(slot, Undefined) + if new_value is Undefined: + continue + elif new_value is old_value: + continue + elif old_value is Undefined: + slot_values[slot] = new_value + # If we already know we have to re-validate abort + # early to avoid costly lookups + if slot_overridden or type_change: + break + else: + if slot not in param._non_validated_slots: + slot_overridden = True + break + + if slot_values.get(slot, Undefined) is Undefined: + try: + default_val = param._slot_defaults[slot] + except KeyError as e: + raise KeyError( + f'Slot {slot!r} of parameter {param_name!r} has no ' + 'default value defined in `_slot_defaults`' + ) from e + if callable(default_val): + callables[slot] = default_val + else: + slot_values[slot] = default_val + elif slot == 'allow_refs' and not slot_values[slot]: + # Track Parameters that explicitly declared no refs + mcs._param__private.explicit_no_refs.append(param.name) + + # Now set the actual slot values + for slot, value in slot_values.items(): + setattr(param, slot, value) + + # Avoid crosstalk between mutable slot values in different Parameter objects + if slot != "default": + v = getattr(param, slot) + if _is_mutable_container(v): + setattr(param, slot, copy.copy(v)) + + # Once all the static slots have been filled in, fill in the dynamic ones + # (which are only allowed to use static values or results are undefined) + for slot, fn in callables.items(): + setattr(param, slot, fn(param)) + + # Once all the slot values have been set, call _update_state for Parameters + # that need updates to make sure they're set up correctly after inheritance. + param._update_state() + + # If the type has changed to a more specific or different type + # or a slot value has been changed validate the default again. + + # Hack: Had to disable re-validation of None values because the + # automatic appending of an unknown value on Selector opens a whole + # rabbit hole in regard to the validation. + if type_change or slot_overridden and param.default is not None: + param._validate(param.default) + + def get_param_descriptor(mcs,param_name): + """ + Goes up the class hierarchy (starting from the current class) + looking for a Parameter class attribute param_name. As soon as + one is found as a class attribute, that Parameter is returned + along with the class in which it is declared. + """ + classes = classlist(mcs) + for c in classes[::-1]: + attribute = c.__dict__.get(param_name) + if isinstance(attribute,Parameter): + return attribute,c + return None,None + + + +# Whether script_repr should avoid reporting the values of parameters +# that are just inheriting their values from the class defaults. +# Because deepcopying creates a new object, cannot detect such +# inheritance when instantiate = True, so such values will be printed +# even if they are just being copied from the default. +script_repr_suppress_defaults=True + + +
[docs]def script_repr(val, imports=None, prefix="\n ", settings=[], + qualify=True, unknown_value=None, separator="\n", + show_imports=True): + """ + Variant of pprint() designed for generating a (nearly) runnable script. + + The output of script_repr(parameterized_obj) is meant to be a + string suitable for running using `python file.py`. Not every + object is guaranteed to have a runnable script_repr + representation, but it is meant to be a good starting point for + generating a Python script that (after minor edits) can be + evaluated to get a newly initialized object similar to the one + provided. + + The new object will only have the same parameter state, not the + same internal (attribute) state; the script_repr captures only + the state of the Parameters of that object and not any other + attributes it may have. + + If show_imports is True (default), includes import statements + for each of the modules required for the objects being + instantiated. This list may not be complete, as it typically + includes only the imports needed for the Parameterized object + itself, not for values that may have been supplied to Parameters. + + Apart from show_imports, accepts the same arguments as pprint(), + so see pprint() for explanations of the arguments accepted. The + default values of each of these arguments differ from pprint() in + ways that are more suitable for saving as a separate script than + for e.g. pretty-printing at the Python prompt. + """ + + if imports is None: + imports = [] + + rep = pprint(val, imports, prefix, settings, unknown_value, + qualify, separator) + + imports = list(set(imports)) + imports_str = ("\n".join(imports) + "\n\n") if show_imports else "" + + return imports_str + rep
+ + +# PARAM2_DEPRECATION: Remove entirely unused settings argument +def pprint(val,imports=None, prefix="\n ", settings=[], + unknown_value='<?>', qualify=False, separator=''): + """ + Pretty printed representation of a parameterized + object that may be evaluated with eval. + + Similar to repr except introspection of the constructor (__init__) + ensures a valid and succinct representation is generated. + + Only parameters are represented (whether specified as standard, + positional, or keyword arguments). Parameters specified as + positional arguments are always shown, followed by modified + parameters specified as keyword arguments, sorted by precedence. + + unknown_value determines what to do where a representation cannot be + generated for something required to recreate the object. Such things + include non-parameter positional and keyword arguments, and certain + values of parameters (e.g. some random state objects). + + Supplying an unknown_value of None causes unrepresentable things + to be silently ignored. If unknown_value is a string, that + string will appear in place of any unrepresentable things. If + unknown_value is False, an Exception will be raised if an + unrepresentable value is encountered. + + If supplied, imports should be a list, and it will be populated + with the set of imports required for the object and all of its + parameter values. + + If qualify is True, the class's path will be included (e.g. "a.b.C()"), + otherwise only the class will appear ("C()"). + + Parameters will be separated by a comma only by default, but the + separator parameter allows an additional separator to be supplied + (e.g. a newline could be supplied to have each Parameter appear on a + separate line). + + Instances of types that require special handling can use the + script_repr_reg dictionary. Using the type as a key, add a + function that returns a suitable representation of instances of + that type, and adds the required import statement. The repr of a + parameter can be suppressed by returning None from the appropriate + hook in script_repr_reg. + """ + + if imports is None: + imports = [] + + if isinstance(val,type): + rep = type_script_repr(val,imports,prefix,settings) + + elif type(val) in script_repr_reg: + rep = script_repr_reg[type(val)](val,imports,prefix,settings) + + elif isinstance(val, Parameterized) or (type(val) is type and issubclass(val, Parameterized)): + rep=val.param.pprint(imports=imports, prefix=prefix+" ", + qualify=qualify, unknown_value=unknown_value, + separator=separator) + else: + rep=repr(val) + + return rep + + +# Registry for special handling for certain types in script_repr and pprint +script_repr_reg = {} + + +# currently only handles list and tuple +def container_script_repr(container,imports,prefix,settings): + result=[] + for i in container: + result.append(pprint(i,imports,prefix,settings)) + + ## (hack to get container brackets) + if isinstance(container,list): + d1,d2='[',']' + elif isinstance(container,tuple): + d1,d2='(',')' + else: + raise NotImplementedError + rep=d1+','.join(result)+d2 + + # no imports to add for built-in types + + return rep + + +def empty_script_repr(*args): # pyflakes:ignore (unused arguments): + return None + +try: + # Suppress scriptrepr for objects not yet having a useful string representation + import numpy + script_repr_reg[random.Random] = empty_script_repr + script_repr_reg[numpy.random.RandomState] = empty_script_repr + +except ImportError: + pass # Support added only if those libraries are available + + +def function_script_repr(fn,imports,prefix,settings): + name = fn.__name__ + module = fn.__module__ + imports.append('import %s'%module) + return module+'.'+name + +def type_script_repr(type_,imports,prefix,settings): + module = type_.__module__ + if module!='__builtin__': + imports.append('import %s'%module) + return module+'.'+type_.__name__ + +script_repr_reg[list] = container_script_repr +script_repr_reg[tuple] = container_script_repr +script_repr_reg[FunctionType] = function_script_repr + + +#: If not None, the value of this Parameter will be called (using '()') +#: before every call to __db_print, and is expected to evaluate to a +#: string that is suitable for prefixing messages and warnings (such +#: as some indicator of the global state). +dbprint_prefix=None + + +def truncate(str_, maxlen = 30): + """Return HTML-safe truncated version of given string""" + rep = (str_[:(maxlen-2)] + '..') if (len(str_) > (maxlen-2)) else str_ + return html.escape(rep) + + +def _get_param_repr(key, val, p, vallen=30, doclen=40): + """HTML representation for a single Parameter object and its value""" + if isinstance(val, Parameterized) or (type(val) is type and issubclass(val, Parameterized)): + value = val.param._repr_html_(open=False) + elif hasattr(val, "_repr_html_"): + value = val._repr_html_() + else: + value = truncate(repr(val), vallen) + + if hasattr(p, 'bounds'): + if p.bounds is None: + range_ = '' + elif hasattr(p,'inclusive_bounds'): + # Numeric bounds use ( and [ to indicate exclusive and inclusive + bl,bu = p.bounds + il,iu = p.inclusive_bounds + + lb = '' if bl is None else ('>=' if il else '>') + str(bl) + ub = '' if bu is None else ('<=' if iu else '<') + str(bu) + range_ = lb + (', ' if lb and bu else '') + ub + else: + range_ = repr(p.bounds) + elif hasattr(p, 'objects') and p.objects: + range_ = ', '.join(list(map(repr, p.objects))) + elif hasattr(p, 'class_'): + if isinstance(p.class_, tuple): + range_ = ' | '.join(kls.__name__ for kls in p.class_) + else: + range_ = p.class_.__name__ + elif hasattr(p, 'regex') and p.regex is not None: + range_ = f'regex({p.regex})' + else: + range_ = '' + + if p.readonly: + range_ = ' '.join(s for s in ['<i>read-only</i>', range_] if s) + elif p.constant: + range_ = ' '.join(s for s in ['<i>constant</i>', range_] if s) + + if getattr(p, 'allow_None', False): + range_ = ' '.join(s for s in ['<i>nullable</i>', range_] if s) + + tooltip = f' class="param-doc-tooltip" data-tooltip="{escape(p.doc.strip())}"' if p.doc else '' + + return ( + f'<tr>' + f' <td><p style="margin-bottom: 0px;"{tooltip}>{key}</p></td>' + f' <td style="max-width: 200px; text-align:left;">{value}</td>' + f' <td style="text-align:left;">{p.__class__.__name__}</td>' + f' <td style="max-width: 300px;">{range_}</td>' + f'</tr>\n' + ) + + +def _parameterized_repr_html(p, open): + """HTML representation for a Parameterized object""" + if isinstance(p, Parameterized): + cls = p.__class__ + title = cls.name + "()" + value_field = 'Value' + else: + cls = p + title = cls.name + value_field = 'Default' + + tooltip_css = """ +.param-doc-tooltip{ + position: relative; + cursor: help; +} +.param-doc-tooltip:hover:after{ + content: attr(data-tooltip); + background-color: black; + color: #fff; + border-radius: 3px; + padding: 10px; + position: absolute; + z-index: 1; + top: -5px; + left: 100%; + margin-left: 10px; + min-width: 250px; +} +.param-doc-tooltip:hover:before { + content: ""; + position: absolute; + top: 50%; + left: 100%; + margin-top: -5px; + border-width: 5px; + border-style: solid; + border-color: transparent black transparent transparent; +} +""" + openstr = " open" if open else "" + param_values = p.param.values().items() + contents = "".join(_get_param_repr(key, val, p.param[key]) + for key, val in param_values) + return ( + f'<style>{tooltip_css}</style>\n' + f'<details {openstr}>\n' + ' <summary style="display:list-item; outline:none;">\n' + f' <tt>{title}</tt>\n' + ' </summary>\n' + ' <div style="padding-left:10px; padding-bottom:5px;">\n' + ' <table style="max-width:100%; border:1px solid #AAAAAA;">\n' + f' <tr><th style="text-align:left;">Name</th><th style="text-align:left;">{value_field}</th><th style="text-align:left;">Type</th><th>Range</th></tr>\n' + f'{contents}\n' + ' </table>\n </div>\n</details>\n' + ) + +# _ClassPrivate and _InstancePrivate are the private namespaces of Parameterized +# classes and instance respectively, stored on the `_param__private` attribute. +# They are implemented with slots for performance reasons. + +class _ClassPrivate: + """ + parameters_state: dict + Dict holding some transient states + disable_instance_params: bool + Whether to disable instance parameters + renamed: bool + Whethe the class has been renamed by a super class + params: dict + Dict of parameter_name:parameter + """ + + __slots__ = [ + 'parameters_state', + 'disable_instance_params', + 'renamed', + 'params', + 'initialized', + 'signature', + 'explicit_no_refs', + ] + + def __init__( + self, + parameters_state=None, + disable_instance_params=False, + explicit_no_refs=None, + renamed=False, + params=None, + ): + if parameters_state is None: + parameters_state = { + "BATCH_WATCH": False, # If true, Event and watcher objects are queued. + "TRIGGER": False, + "events": [], # Queue of batched events + "watchers": [] # Queue of batched watchers + } + self.parameters_state = parameters_state + self.disable_instance_params = disable_instance_params + self.renamed = renamed + self.params = {} if params is None else params + self.initialized = False + self.signature = None + self.explicit_no_refs = [] if explicit_no_refs is None else explicit_no_refs + + def __getstate__(self): + return {slot: getattr(self, slot) for slot in self.__slots__} + + def __setstate__(self, state): + for k, v in state.items(): + setattr(self, k, v) + + +class _InstancePrivate: + """ + initialized: bool + Flag that can be tested to see if e.g. constant Parameters can still be set + parameters_state: dict + Dict holding some transient states + dynamic_watchers: defaultdict + Dynamic watchers + ref_watchers: list[Watcher] + Watchers used for internal references + params: dict + Dict of parameter_name:parameter + refs: dict + Dict of parameter name:reference + watchers: dict + Dict of dict: + parameter_name: + parameter_attribute (e.g. 'value'): list of `Watcher`s + values: dict + Dict of parameter name: value + """ + + __slots__ = [ + 'initialized', + 'parameters_state', + 'dynamic_watchers', + 'params', + 'async_refs', + 'refs', + 'ref_watchers', + 'syncing', + 'watchers', + 'values', + ] + + def __init__( + self, + initialized=False, + parameters_state=None, + dynamic_watchers=None, + refs=None, + params=None, + watchers=None, + values=None, + ): + self.initialized = initialized + self.syncing = set() + if parameters_state is None: + parameters_state = { + "BATCH_WATCH": False, # If true, Event and watcher objects are queued. + "TRIGGER": False, + "events": [], # Queue of batched events + "watchers": [] # Queue of batched watchers + } + self.ref_watchers = [] + self.async_refs = {} + self.parameters_state = parameters_state + self.dynamic_watchers = defaultdict(list) if dynamic_watchers is None else dynamic_watchers + self.params = {} if params is None else params + self.refs = {} if refs is None else refs + self.watchers = {} if watchers is None else watchers + self.values = {} if values is None else values + + def __getstate__(self): + return {slot: getattr(self, slot) for slot in self.__slots__} + + def __setstate__(self, state): + for k, v in state.items(): + setattr(self, k, v) + + +
[docs]class Parameterized(metaclass=ParameterizedMetaclass): + """ + Base class for named objects that support Parameters and message + formatting. + + Automatic object naming: Every Parameterized instance has a name + parameter. If the user doesn't designate a name=<str> argument + when constructing the object, the object will be given a name + consisting of its class name followed by a unique 5-digit number. + + Automatic parameter setting: The Parameterized __init__ method + will automatically read the list of keyword parameters. If any + keyword matches the name of a Parameter (see Parameter class) + defined in the object's class or any of its superclasses, that + parameter in the instance will get the value given as a keyword + argument. For example: + + class Foo(Parameterized): + xx = Parameter(default=1) + + foo = Foo(xx=20) + + in this case foo.xx gets the value 20. + + When initializing a Parameterized instance ('foo' in the example + above), the values of parameters can be supplied as keyword + arguments to the constructor (using parametername=parametervalue); + these values will override the class default values for this one + instance. + + If no 'name' parameter is supplied, self.name defaults to the + object's class name with a unique number appended to it. + + Message formatting: Each Parameterized instance has several + methods for optionally printing output. This functionality is + based on the standard Python 'logging' module; using the methods + provided here, wraps calls to the 'logging' module's root logger + and prepends each message with information about the instance + from which the call was made. For more information on how to set + the global logging level and change the default message prefix, + see documentation for the 'logging' module. + """ + + name = String(default=None, constant=True, doc=""" + String identifier for this object.""") + +
[docs] def __init__(self, **params): + global object_count + + # Setting a Parameter value in an __init__ block before calling + # Parameterized.__init__ (via super() generally) already sets the + # _InstancePrivate namespace over the _ClassPrivate namespace + # (see Parameter.__set__) so we shouldn't override it here. + if not isinstance(self._param__private, _InstancePrivate): + self._param__private = _InstancePrivate() + + # Skip generating a custom instance name when a class in the hierarchy + # has overriden the default of the `name` Parameter. + if self.param.name.default == self.__class__.__name__: + self.param._generate_name() + refs, deps = self.param._setup_params(**params) + object_count += 1 + + self._param__private.initialized = True + + self.param._setup_refs(deps) + self.param._update_deps(init=True) + self._param__private.refs = refs
+ + @property + def param(self): + return Parameters(self.__class__, self=self) + + #PARAM3_DEPRECATION + @property + @_deprecated(extra_msg="Use `inst.param.watchers` instead.", warning_cat=FutureWarning) + def _param_watchers(self): + return self._param__private.watchers + + #PARAM3_DEPRECATION + @_param_watchers.setter + @_deprecated(extra_msg="Use `inst.param.watchers = ...` instead.", warning_cat=FutureWarning) + def _param_watchers(self, value): + self._param__private.watchers = value + + # 'Special' methods + + def __getstate__(self): + """ + Save the object's state: return a dictionary that is a shallow + copy of the object's __dict__ and that also includes the + object's __slots__ (if it has any). + """ + # Unclear why this is a copy and not simply state.update(self.__dict__) + state = self.__dict__.copy() + for slot in get_occupied_slots(self): + state[slot] = getattr(self,slot) + + # Note that Parameterized object pickling assumes that + # attributes to be saved are only in __dict__ or __slots__ + # (the standard Python places to store attributes, so that's a + # reasonable assumption). (Additionally, class attributes that + # are Parameters are also handled, even when they haven't been + # instantiated - see PickleableClassAttributes.) + + return state + + def __setstate__(self, state): + """ + Restore objects from the state dictionary to this object. + + During this process the object is considered uninitialized. + """ + self._param__private = _InstancePrivate() + self._param__private.initialized = False + + _param__private = state.get('_param__private', None) + if _param__private is None: + _param__private = _InstancePrivate() + + # When making a copy the internal watchers have to be + # recreated and point to the new instance + if _param__private.watchers: + param_watchers = _param__private.watchers + for p, attrs in param_watchers.items(): + for attr, watchers in attrs.items(): + new_watchers = [] + for watcher in watchers: + watcher_args = list(watcher) + if watcher.inst is not None: + watcher_args[0] = self + fn = watcher.fn + if hasattr(fn, '_watcher_name'): + watcher_args[2] = _m_caller(self, fn._watcher_name) + elif get_method_owner(fn) is watcher.inst: + watcher_args[2] = getattr(self, fn.__name__) + new_watchers.append(Watcher(*watcher_args)) + param_watchers[p][attr] = new_watchers + + state.pop('param', None) + + for name,value in state.items(): + setattr(self,name,value) + self._param__private.initialized = True + + @_recursive_repr() + def __repr__(self): + """ + Provide a nearly valid Python representation that could be used to recreate + the item with its parameters, if executed in the appropriate environment. + + Returns 'classname(parameter1=x,parameter2=y,...)', listing + all the parameters of this object. + """ + try: + settings = [f'{name}={val!r}' + for name, val in self.param.values().items()] + except RuntimeError: # Handle recursion in parameter depth + settings = [] + return self.__class__.__name__ + "(" + ", ".join(settings) + ")" + + def __str__(self): + """Return a short representation of the name and class of this object.""" + return f"<{self.__class__.__name__} {self.name}>"
+ + +def print_all_param_defaults(): + """Print the default values for all imported Parameters.""" + print("_______________________________________________________________________________") + print("") + print(" Parameter Default Values") + print("") + classes = descendents(Parameterized) + classes.sort(key=lambda x:x.__name__) + for c in classes: + c.print_param_defaults() + print("_______________________________________________________________________________") + + + +# As of Python 2.6+, a fn's **args no longer has to be a +# dictionary. This might allow us to use a decorator to simplify using +# ParamOverrides (if that does indeed make them simpler to use). +# http://docs.python.org/whatsnew/2.6.html +
[docs]class ParamOverrides(dict): + """ + A dictionary that returns the attribute of a specified object if + that attribute is not present in itself. + + Used to override the parameters of an object. + """ + + # NOTE: Attribute names of this object block parameters of the + # same name, so all attributes of this object should have names + # starting with an underscore (_). + +
[docs] def __init__(self,overridden,dict_,allow_extra_keywords=False): + """ + + If allow_extra_keywords is False, then all keys in the + supplied dict_ must match parameter names on the overridden + object (otherwise a warning will be printed). + + If allow_extra_keywords is True, then any items in the + supplied dict_ that are not also parameters of the overridden + object will be available via the extra_keywords() method. + """ + # This method should be fast because it's going to be + # called a lot. This _might_ be faster (not tested): + # def __init__(self,overridden,**kw): + # ... + # dict.__init__(self,**kw) + self._overridden = overridden + dict.__init__(self,dict_) + + if allow_extra_keywords: + self._extra_keywords=self._extract_extra_keywords(dict_) + else: + self._check_params(dict_)
+ + def extra_keywords(self): + """ + Return a dictionary containing items from the originally + supplied `dict_` whose names are not parameters of the + overridden object. + """ + return self._extra_keywords + + def param_keywords(self): + """ + Return a dictionary containing items from the originally + supplied `dict_` whose names are parameters of the + overridden object (i.e. not extra keywords/parameters). + """ + return {key: self[key] for key in self if key not in self.extra_keywords()} + + def __missing__(self,name): + # Return 'name' from the overridden object + return getattr(self._overridden,name) + + def __repr__(self): + # As dict.__repr__, but indicate the overridden object + return dict.__repr__(self)+" overriding params from %s"%repr(self._overridden) + + def __getattr__(self,name): + # Provide 'dot' access to entries in the dictionary. + # (This __getattr__ method is called only if 'name' isn't an + # attribute of self.) + return self.__getitem__(name) + + def __setattr__(self,name,val): + # Attributes whose name starts with _ are set on self (as + # normal), but all other attributes are inserted into the + # dictionary. + if not name.startswith('_'): + self.__setitem__(name,val) + else: + dict.__setattr__(self,name,val) + + def get(self, key, default=None): + try: + return self[key] + except KeyError: + return default + + def __contains__(self, key): + return key in self.__dict__ or key in self._overridden.param + + def _check_params(self,params): + """ + Print a warning if params contains something that is not a + Parameter of the overridden object. + """ + overridden_object_params = list(self._overridden.param) + for item in params: + if item not in overridden_object_params: + self.param.warning("'%s' will be ignored (not a Parameter).",item) + + def _extract_extra_keywords(self,params): + """ + Return any items in params that are not also + parameters of the overridden object. + """ + extra_keywords = {} + overridden_object_params = list(self._overridden.param) + for name, val in params.items(): + if name not in overridden_object_params: + extra_keywords[name]=val + # Could remove name from params (i.e. del params[name]) + # so that it's only available via extra_keywords() + return extra_keywords
+ + +# Helper function required by ParameterizedFunction.__reduce__ +def _new_parameterized(cls): + return Parameterized.__new__(cls) + + +
[docs]class ParameterizedFunction(Parameterized): + """ + Acts like a Python function, but with arguments that are Parameters. + + Implemented as a subclass of Parameterized that, when instantiated, + automatically invokes __call__ and returns the result, instead of + returning an instance of the class. + + To obtain an instance of this class, call instance(). + """ + __abstract = True + + def __str__(self): + return self.__class__.__name__+"()" + + @bothmethod + def instance(self_or_cls,**params): + """ + Return an instance of this class, copying parameters from any + existing instance provided. + """ + + if isinstance (self_or_cls,ParameterizedMetaclass): + cls = self_or_cls + else: + p = params + params = self_or_cls.param.values() + params.update(p) + params.pop('name') + cls = self_or_cls.__class__ + + inst=Parameterized.__new__(cls) + Parameterized.__init__(inst,**params) + if 'name' in params: inst.__name__ = params['name'] + else: inst.__name__ = self_or_cls.name + return inst + + def __new__(class_,*args,**params): + # Create and __call__() an instance of this class. + inst = class_.instance() + inst.param._set_name(class_.__name__) + return inst.__call__(*args,**params) + + def __call__(self,*args,**kw): + raise NotImplementedError("Subclasses must implement __call__.") + + def __reduce__(self): + # Control reconstruction (during unpickling and copying): + # ensure that ParameterizedFunction.__new__ is skipped + state = ParameterizedFunction.__getstate__(self) + # Here it's necessary to use a function defined at the + # module level rather than Parameterized.__new__ directly + # because otherwise pickle will find .__new__'s module to be + # __main__. Pretty obscure aspect of pickle.py... + return (_new_parameterized,(self.__class__,),state) + + def _pprint(self, imports=None, prefix="\n ",unknown_value='<?>', + qualify=False, separator=""): + """ + Same as self.param.pprint, except that X.classname(Y + is replaced with X.classname.instance(Y + """ + r = self.param.pprint(imports,prefix, + unknown_value=unknown_value, + qualify=qualify,separator=separator) + classname=self.__class__.__name__ + return r.replace(".%s("%classname,".%s.instance("%classname)
+ + +class default_label_formatter(ParameterizedFunction): + "Default formatter to turn parameter names into appropriate widget labels." + + capitalize = Parameter(default=True, doc=""" + Whether or not the label should be capitalized.""") + + replace_underscores = Parameter(default=True, doc=""" + Whether or not underscores should be replaced with spaces.""") + + overrides = Parameter(default={}, doc=""" + Allows custom labels to be specified for specific parameter + names using a dictionary where key is the parameter name and the + value is the desired label.""") + + def __call__(self, pname): + if pname in self.overrides: + return self.overrides[pname] + if self.replace_underscores: + pname = pname.replace('_',' ') + if self.capitalize: + pname = pname[:1].upper() + pname[1:] + return pname + + +label_formatter = default_label_formatter + + +# PARAM3_DEPRECATION: Should be able to remove this; was originally +# adapted from OProperty from +# infinitesque.net/articles/2005/enhancing%20Python's%20property.xhtml +# but since python 2.6 the getter, setter, and deleter attributes of +# a property should provide similar functionality already. +class overridable_property: + """ + The same as Python's "property" attribute, but allows the accessor + methods to be overridden in subclasses. + + .. deprecated:: 2.0.0 + """ + # Delays looking up the accessors until they're needed, rather + # than finding them when the class is first created. + + # Based on the emulation of PyProperty_Type() in Objects/descrobject.c + + def __init__(self, fget=None, fset=None, fdel=None, doc=None): + warnings.warn( + message="overridable_property has been deprecated.", + category=_ParamDeprecationWarning, + stacklevel=2, + ) + self.fget = fget + self.fset = fset + self.fdel = fdel + self.__doc__ = doc + + def __get__(self, obj, objtype=None): + if obj is None: + return self + if self.fget is None: + raise AttributeError("unreadable attribute") + if self.fget.__name__ == '<lambda>' or not self.fget.__name__: + return self.fget(obj) + else: + return getattr(obj, self.fget.__name__)() + + def __set__(self, obj, value): + if self.fset is None: + raise AttributeError("can't set attribute") + if self.fset.__name__ == '<lambda>' or not self.fset.__name__: + self.fset(obj, value) + else: + getattr(obj, self.fset.__name__)(value) + + def __delete__(self, obj): + if self.fdel is None: + raise AttributeError("can't delete attribute") + if self.fdel.__name__ == '<lambda>' or not self.fdel.__name__: + self.fdel(obj) + else: + getattr(obj, self.fdel.__name__)() +
+ +
+ + + +
+ +
+ +
+
+
+ +
+ +
+ +
+ + + + +
+ + +
+
+
+ + + + + + + + \ No newline at end of file diff --git a/_modules/param/serializer.html b/_modules/param/serializer.html new file mode 100644 index 0000000..1dfa10e --- /dev/null +++ b/_modules/param/serializer.html @@ -0,0 +1,985 @@ + + + + + + + + + + + param.serializer — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +

Source code for param.serializer

+"""
+Classes used to support string serialization of Parameters and
+Parameterized objects.
+"""
+
+import json
+import textwrap
+
+
[docs]class UnserializableException(Exception): + pass
+ +
[docs]class UnsafeserializableException(Exception): + pass
+ +
[docs]def JSONNullable(json_type): + "Express a JSON schema type as nullable to easily support Parameters that allow_None" + return {'anyOf': [ json_type, {'type': 'null'}] }
+ + + +
[docs]class Serialization: + """ + Base class used to implement different types of serialization. + """ + +
[docs] @classmethod + def schema(cls, pobj, subset=None): + raise NotImplementedError # noqa: unimplemented method
+ +
[docs] @classmethod + def serialize_parameters(cls, pobj, subset=None): + """ + Serialize the parameters on a Parameterized object into a + single serialized object, e.g. a JSON string. + """ + raise NotImplementedError # noqa: unimplemented method
+ +
[docs] @classmethod + def deserialize_parameters(cls, pobj, serialized, subset=None): + """ + Deserialize a serialized object representing one or + more Parameters into a dictionary of parameter values. + """ + raise NotImplementedError # noqa: unimplemented method
+ +
[docs] @classmethod + def serialize_parameter_value(cls, pobj, pname): + """ + Serialize a single parameter value. + """ + raise NotImplementedError # noqa: unimplemented method
+ +
[docs] @classmethod + def deserialize_parameter_value(cls, pobj, pname, value): + """ + Deserialize a single parameter value. + """ + raise NotImplementedError # noqa: unimplemented method
+ + +
[docs]class JSONSerialization(Serialization): + """ + Class responsible for specifying JSON serialization, deserialization + and JSON schemas for Parameters and Parameterized classes and + objects. + """ + + unserializable_parameter_types = ['Callable'] + + json_schema_literal_types = { + int:'integer', float:'number', str:'string', + type(None): 'null' + } + +
[docs] @classmethod + def loads(cls, serialized): + return json.loads(serialized)
+ +
[docs] @classmethod + def dumps(cls, obj): + return json.dumps(obj)
+ +
[docs] @classmethod + def schema(cls, pobj, safe=False, subset=None): + schema = {} + for name, p in pobj.param.objects('existing').items(): + if subset is not None and name not in subset: + continue + schema[name] = p.schema(safe=safe) + if p.doc: + schema[name]['description'] = textwrap.dedent(p.doc).replace('\n', ' ').strip() + if p.label: + schema[name]['title'] = p.label + return schema
+ +
[docs] @classmethod + def serialize_parameters(cls, pobj, subset=None): + components = {} + for name, p in pobj.param.objects('existing').items(): + if subset is not None and name not in subset: + continue + value = pobj.param.get_value_generator(name) + components[name] = p.serialize(value) + return cls.dumps(components)
+ +
[docs] @classmethod + def deserialize_parameters(cls, pobj, serialization, subset=None): + deserialized = cls.loads(serialization) + components = {} + for name, value in deserialized.items(): + if subset is not None and name not in subset: + continue + deserialized = pobj.param[name].deserialize(value) + components[name] = deserialized + return components
+ + # Parameter level methods + + @classmethod + def _get_method(cls, ptype, suffix): + "Returns specialized method if available, otherwise None" + method_name = ptype.lower()+'_' + suffix + return getattr(cls, method_name, None) + +
[docs] @classmethod + def param_schema(cls, ptype, p, safe=False, subset=None): + if ptype in cls.unserializable_parameter_types: + raise UnserializableException + dispatch_method = cls._get_method(ptype, 'schema') + if dispatch_method: + schema = dispatch_method(p, safe=safe) + else: + schema = {'type': ptype.lower()} + return JSONNullable(schema) if p.allow_None else schema
+ +
[docs] @classmethod + def serialize_parameter_value(cls, pobj, pname): + value = pobj.param.get_value_generator(pname) + return cls.dumps(pobj.param[pname].serialize(value))
+ +
[docs] @classmethod + def deserialize_parameter_value(cls, pobj, pname, value): + value = cls.loads(value) + return pobj.param[pname].deserialize(value)
+ + # Custom Schemas + +
[docs] @classmethod + def class__schema(cls, class_, safe=False): + from .parameterized import Parameterized + if isinstance(class_, tuple): + return {'anyOf': [cls.class__schema(cls_) for cls_ in class_]} + elif class_ in cls.json_schema_literal_types: + return {'type': cls.json_schema_literal_types[class_]} + elif issubclass(class_, Parameterized): + return {'type': 'object', 'properties': class_.param.schema(safe)} + else: + return {'type': 'object'}
+ +
[docs] @classmethod + def array_schema(cls, p, safe=False): + if safe is True: + msg = ('Array is not guaranteed to be safe for ' + 'serialization as the dtype is unknown') + raise UnsafeserializableException(msg) + return {'type': 'array'}
+ +
[docs] @classmethod + def classselector_schema(cls, p, safe=False): + return cls.class__schema(p.class_, safe=safe)
+ +
[docs] @classmethod + def dict_schema(cls, p, safe=False): + if safe is True: + msg = ('Dict is not guaranteed to be safe for ' + 'serialization as the key and value types are unknown') + raise UnsafeserializableException(msg) + return {'type': 'object'}
+ +
[docs] @classmethod + def date_schema(cls, p, safe=False): + return {'type': 'string', 'format': 'date-time'}
+ +
[docs] @classmethod + def calendardate_schema(cls, p, safe=False): + return {'type': 'string', 'format': 'date'}
+ +
[docs] @classmethod + def tuple_schema(cls, p, safe=False): + schema = {'type': 'array'} + if p.length is not None: + schema['minItems'] = p.length + schema['maxItems'] = p.length + return schema
+ +
[docs] @classmethod + def number_schema(cls, p, safe=False): + schema = {'type': p.__class__.__name__.lower() } + return cls.declare_numeric_bounds(schema, p.bounds, p.inclusive_bounds)
+ +
[docs] @classmethod + def declare_numeric_bounds(cls, schema, bounds, inclusive_bounds): + "Given an applicable numeric schema, augment with bounds information" + if bounds is not None: + (low, high) = bounds + if low is not None: + key = 'minimum' if inclusive_bounds[0] else 'exclusiveMinimum' + schema[key] = low + if high is not None: + key = 'maximum' if inclusive_bounds[1] else 'exclusiveMaximum' + schema[key] = high + return schema
+ +
[docs] @classmethod + def integer_schema(cls, p, safe=False): + return cls.number_schema(p)
+ +
[docs] @classmethod + def numerictuple_schema(cls, p, safe=False): + schema = cls.tuple_schema(p, safe=safe) + schema['additionalItems'] = {'type': 'number'} + return schema
+ +
[docs] @classmethod + def xycoordinates_schema(cls, p, safe=False): + return cls.numerictuple_schema(p, safe=safe)
+ +
[docs] @classmethod + def range_schema(cls, p, safe=False): + schema = cls.tuple_schema(p, safe=safe) + bounded_number = cls.declare_numeric_bounds( + {'type': 'number'}, p.bounds, p.inclusive_bounds) + schema['additionalItems'] = bounded_number + return schema
+ +
[docs] @classmethod + def list_schema(cls, p, safe=False): + schema = {'type': 'array'} + if safe is True and p.item_type is None: + msg = ('List without a class specified cannot be guaranteed ' + 'to be safe for serialization') + raise UnsafeserializableException(msg) + if p.class_ is not None: + schema['items'] = cls.class__schema(p.item_type, safe=safe) + return schema
+ +
[docs] @classmethod + def objectselector_schema(cls, p, safe=False): + try: + allowed_types = [{'type': cls.json_schema_literal_types[type(obj)]} + for obj in p.objects] + schema = {'anyOf': allowed_types} + schema['enum'] = p.objects + return schema + except: + if safe is True: + msg = ('ObjectSelector cannot be guaranteed to be safe for ' + 'serialization due to unserializable type in objects') + raise UnsafeserializableException(msg) + return {}
+ +
[docs] @classmethod + def selector_schema(cls, p, safe=False): + try: + allowed_types = [{'type': cls.json_schema_literal_types[type(obj)]} + for obj in p.objects.values()] + schema = {'anyOf': allowed_types} + schema['enum'] = p.objects + return schema + except: + if safe is True: + msg = ('Selector cannot be guaranteed to be safe for ' + 'serialization due to unserializable type in objects') + raise UnsafeserializableException(msg) + return {}
+ +
[docs] @classmethod + def listselector_schema(cls, p, safe=False): + if p.objects is None: + if safe is True: + msg = ('ListSelector cannot be guaranteed to be safe for ' + 'serialization as allowed objects unspecified') + return {'type': 'array'} + for obj in p.objects: + if type(obj) not in cls.json_schema_literal_types: + msg = 'ListSelector cannot serialize type %s' % type(obj) + raise UnserializableException(msg) + return {'type': 'array', 'items': {'enum': p.objects}}
+ +
[docs] @classmethod + def dataframe_schema(cls, p, safe=False): + schema = {'type': 'array'} + if safe is True: + msg = ('DataFrame is not guaranteed to be safe for ' + 'serialization as the column dtypes are unknown') + raise UnsafeserializableException(msg) + if p.columns is None: + schema['items'] = {'type': 'object'} + return schema + + mincols, maxcols = None, None + if isinstance(p.columns, int): + mincols, maxcols = p.columns, p.columns + elif isinstance(p.columns, tuple): + mincols, maxcols = p.columns + + if isinstance(p.columns, int) or isinstance(p.columns, tuple): + schema['items'] = {'type': 'object', 'minItems': mincols, + 'maxItems': maxcols} + + if isinstance(p.columns, list) or isinstance(p.columns, set): + literal_types = [{'type':el} for el in cls.json_schema_literal_types.values()] + allowable_types = {'anyOf': literal_types} + properties = {name: allowable_types for name in p.columns} + schema['items'] = {'type': 'object', 'properties': properties} + + minrows, maxrows = None, None + if isinstance(p.rows, int): + minrows, maxrows = p.rows, p.rows + elif isinstance(p.rows, tuple): + minrows, maxrows = p.rows + + if minrows is not None: + schema['minItems'] = minrows + if maxrows is not None: + schema['maxItems'] = maxrows + + return schema
+
+ +
+ + + +
+ +
+ +
+
+
+ +
+ +
+ +
+ + + + +
+ + +
+
+
+ + + + + + + + \ No newline at end of file diff --git a/_sources/about.md.txt b/_sources/about.md.txt new file mode 100644 index 0000000..8158af9 --- /dev/null +++ b/_sources/about.md.txt @@ -0,0 +1,9 @@ +# About + +Param is completely open source, available under a [BSD license](https://github.com/holoviz/param/blob/main/LICENSE.txt), freely for both commercial and non-commercial use. Param was originally developed at the University of Texas at Austin and the University of Edinburgh with funding from the US National Institutes of Health grant 1R01-MH66991. Param is now maintained by [Anaconda Inc.](https://anaconda.com) and by community contributors. + +Param is maintained as part of the [HoloViz](https://holoviz.org) family of tools. The [holoviz.org](https://holoviz.org) website shows how to use Param together with other libraries to solve complex problems, with detailed tutorials and examples. Each of the HoloViz tools builds on Param, as do many of the example projects at [examples.holoviz.org](https://examples.holoviz.org). + +If you have any questions or usage issues visit the [Param Discourse forum](https://discourse.holoviz.org/c/param), and if you want to report bugs or request new features, first see if it's already in our list of [open issues](https://github.com/holoviz/param/issues) and then add to the issue or open a new one if needed. + +If you like Param and have built something you want to share, tweet a link or screenshot of your latest creation at [@HoloViz_org](https://twitter.com/HoloViz_org). Thanks! diff --git a/_sources/comparisons.md.txt b/_sources/comparisons.md.txt new file mode 100644 index 0000000..a5510ba --- /dev/null +++ b/_sources/comparisons.md.txt @@ -0,0 +1,103 @@ +# Comparison to other approaches + +Param was first developed in 2003 for Python 2.1 as part of a long-running brain simulation [project](http://ioam.github.io/topographica), and was made into a separate package on [Github](https://github.com/holoviz/param/graphs/contributors) in 2012. In the interim a variety of other libraries solving some of the same problems have been developed, including: + +- [Traits](https://github.com/enthought/traits) +- [Traitlets](https://github.com/ipython/traitlets) +- [attrs](https://github.com/python-attrs/attrs) (with optional [attrs-strict](https://github.com/bloomberg/attrs-strict)) +- [Django models](https://docs.djangoproject.com/en/3.1/topics/db/models) +- [Pydantic](https://pydantic-docs.helpmanual.io) + +Plus, Python itself has incorporated mechanisms addressing some of the same issues: + +- [Python 3.6+ type annotations](https://www.python.org/dev/peps/pep-0526/) +- [Python 3.7+ data classes](https://docs.python.org/3/library/dataclasses.html) +- [Python 2.6+ namedtuples](https://docs.python.org/3/library/collections.html#namedtuple-factory-function-for-tuples-with-named-fields) +- [Python 2.2+ properties](https://docs.python.org/3/library/functions.html#property) + +Each of these approaches overlaps with some but by no means all of the functionality provided by Param, as described below. Also see the comparisons provided with [attrs](https://www.attrs.org/en/stable/why.html) and by an [attr user](https://glyph.twistedmatrix.com/2016/08/attrs.html), which were written about `attrs` but also apply just as well to Param (with Param differing in also providing e.g. GUI support as listed below). [Other info](https://threeofwands.com/why-i-use-attrs-instead-of-pydantic/) comparing `attrs` to `pydantic` is also available. + +Here we will use the word "parameter" as a generic term for a Python attribute, a Param Parameter, a Traitlets/HasTraits trait, or an attr `attr.ib`. + + +## Brevity of code + +Python properties can be used to express nearly anything Param or Traitlets can do, but they require at least an order of magnitude more code to do it. You can think of Param and Traitlets as a pre-written implementation of a Python property that implements a configurable parameter. Avoiding having to write that code each time is a big win, because configurable parameters are all over any Python codebase, and Parameter/attr.ib/pydantic/Traits-based approaches lead to much simpler and more maintainable codebases. + +Specifically, where Param or Traitlets can express an automatically validated type and bounds on an attribute in a simple and localized one-line declaration like `a = param.Integer(5, bounds=(1,10))`, implementing the same functionality using properties requires changes to the constructor plus separate explicit `get` and `set` methods, each with at least a half-dozen lines of validation code. Though this get/set/validate code may seem easy to write, it is difficult to read, difficult to maintain, and difficult to make comprehensive or exhaustive. +In practice, most programmers simply skip validation or implement it only partially, leaving their code behaving in undefined ways for unexpected inputs. With Param or Traitlets, you don't have to choose between short/readable/maintainable code and heavily validated code; you can have both for far less work! + +`pydantic` and `attrs` provide many of these same benefits, though `attrs` type and bounds validation is treated as an extra step that is more general but also typically much more verbose. + +## Runtime checking + +Python 3 type annotations allow users to specify types for attributes and function returns, but these types are not normally checked at runtime, and so they do not have the same role of validating user input or programmer error as the type declarations in Params, Traits, Traitlets, pydantic, and attr. They also are limited to the type, so they cannot enforce constraints on range ('state' must be in the list ['Alabama', 'Alaska',...]). Thus even if type hinting is used, programmers still need to write code to actually validate the inputs to functions and methods, which is the role of packages like Param and Traitlets. Note that Pydantic focuses on [generating valid outputs at runtime](https://github.com/samuelcolvin/pydantic/issues/578) rather than detecting invalid inputs, so it may or may not be suitable for the same types of applications as the other libraries discussed here. + + +## Generality and ease of integration with your project + +The various Python features listed above are part of the standard library with the versions indicated above, and so do not add any dependencies at all to your build process, as long as you restrict yourself to the Python versions where that support was added. + +Param, Traitlets, Pydantic, and attrs are all pure Python projects, with minimal dependencies, and so adding them to any project is generally straightforward. They also support a wide range of Python versions, making them usable in cases where the more recent Python-language features are not available. + +Django models offer some of the same ways to declare parameters and generate web-based GUIs (below), but require the extensive Django web framework and normally rely on a database and web server, which in practice limit their usage to users building dedicated web sites, unlike the no-dependency Param and attrs libraries that can be added to Python projects of any type. + +Traits is a very heavyweight solution, requiring installation and C compilation of a large suite of tools, which makes it difficult to include in separate projects. + +## GUI toolkits + +Several of these packages support automatically mapping parameters/traits/attributes into GUI widgets. Although any of them could in principle be supported for any GUI toolkit, only certain GUI interfaces are currently available: + +- Panel: Jupyter and Bokeh-server support for Param, mapping Parameters to widgets and ParameterizedObjects to sets of widgets +- ParamTk: (unsupported) TKinter support for Param +- IPywidgets: Jupyter support for Traitlets, but without automatic mapping from trait to widget +- TraitsUI: wxWidgets and Qt support for Traits + +## Dynamic values + +Param, Traits, Traitlets, Pydantic, and attrs all allow any Python expression to be supplied for initializing parameters, allowing parameter default values to be computed at the time a module is first loaded. Pydantic, Traits, and Traitlets also allow a class author to add code for a given parameter to compute a default value on first access. + + ```python + >>> from time import time, sleep + >>> import traitlets as tr + >>> class A(tr.HasTraits): + ... instantiation_time = tr.Float() + ... @tr.default('instantiation_time') + ... def _look_up_time(self): + ... return time() + ... + >>> a=A() + >>> time() + 1634594159.2040331 + >>> sleep(1) + >>> time() + 1634594165.3485172 + >>> a.instantiation_time + 1634594167.812151 + >>> a.instantiation_time + 1634594167.812151 + >>> sleep(1) + >>> b=A() + >>> b.instantiation_time + 1634594178.427819 + ``` + + +Param's equivalent decorator `@param.depends(on_init=True)` will run a method when the Parameterized class is instantiated, not on first access. +On the other hand, Param does allow fully dynamic values for *any* access to a numeric Parameter instance, not just the original instantiation: + + ```python + >>> from time import time + >>> import param + >>> class A(param.Parameterized): + ... val=param.Number(0) + ... + >>> a=A() + >>> a.val + 0 + >>> a.val=lambda:time() + >>> a.val + 1475587455.437027 + >>> a.val + 1475587456.501314 + ``` diff --git a/_sources/developer_guide.md.txt b/_sources/developer_guide.md.txt new file mode 100644 index 0000000..7dead26 --- /dev/null +++ b/_sources/developer_guide.md.txt @@ -0,0 +1,41 @@ +# Developer guide + +## Setup + +The source code for `Param` is hosted on GitHub. To clone the source repository, issue the following command: + +```bash +git clone https://github.com/holoviz/param.git +``` + +This will create a `param` directory at your file system location. + +`Param` relies on `hatch` to manage the project. Follow the [instructions](https://hatch.pypa.io/latest/install/) to install it. Once installed, run the following command to create the *default* environment and activate it, it contains the dependencies required to develop `Param`: + +```bash +hatch shell +``` + +## Testing + +The simplest way to run the unit tests is to run the following command: + +```bash +hatch run tests +``` + +You can also run the examples tests, i.e. check that the notebooks run without any error, with: + +```bash +hatch run examples +``` + +## Documentation building + +Run the following command to build the documentation: + +```bash +hatch run docs:build +``` + +Once completed, the built site can be found in the `builtdocs` folder. diff --git a/_sources/getting_started.md.txt b/_sources/getting_started.md.txt new file mode 100644 index 0000000..7fa832c --- /dev/null +++ b/_sources/getting_started.md.txt @@ -0,0 +1,128 @@ +# Getting Started + +## Installation + +Param has no required dependencies outside of Python's standard library, and so it is very easy to install. + +Official releases of Param are available from conda ([![defaults version](https://img.shields.io/conda/v/anaconda/param.svg?label=defaults&style=flat&colorB=4488ff)](https://anaconda.org/main/param) [![conda-forge version](https://img.shields.io/conda/v/conda-forge/param.svg?label=conda-forge&colorB=4488ff)](https://anaconda.org/conda-forge/param)) and PyPI ([![PyPI version](https://img.shields.io/pypi/v/param.svg?colorB=cc77dd)](https://pypi.org/project/param/)), and can be installed via: + +``` +conda install param +``` + +or + +``` +pip install param +``` + +## Using Param to get simple, robust code + +The `param` library gives you Parameters, which are used in Parameterized classes. + +A Parameter is a special type of Python class attribute extended to have various optional features such as type and range checking, dynamically generated values, documentation strings, default values, etc., each of which is inherited from parent classes if not specified in a subclass or instance: + +```{code-block} python +import param + +class A(param.Parameterized): + title = param.String(default="sum", doc="Title for the result") + +class B(A): + a = param.Integer(2, bounds=(0, 10), doc="First addend") + b = param.Integer(3, bounds=(0, 10), doc="Second addend") + + def __call__(self): + return self.title + ": " + str(self.a + self.b) +``` + +```{code-block} python +>> o1 = B(b=4, title="Sum") +>> o1.a = 5 +>> o1() +'Sum: 9' +``` + +```{code-block} python +>> o1.b +4 +``` + +As you can see, the Parameters defined here work precisely like any other Python attributes in your code, so it's generally quite straightforward to migrate an existing class to use Param. Just inherit from `param.Parameterized`, then provide an optional `Parameter` declaration for each parameter the object accepts, including ranges and allowed values if appropriate. You only need to declare and document each parameter _once_, at the highest superclass where it applies, and its default value all the other metadata will be inherited by each subclass. + +Once you've declared your parameters, a whole wealth of features and better behavior is now unlocked! For instance, what happens if a user tries to supply some inappropriate data? With Param, such errors will be caught immediately: + +```{code-block} python +>>> B(a="four") +ValueError: Parameter 'a' must be an integer. + +>>> o2 = B() +>>> o2.b = -5 +ValueError: Parameter 'b' must be at least 0 +``` + +Of course, you could always add more code to an ordinary Python class to check for errors like that, but as described in the [User Guide](user_guide/Simplifying_Codebases), that quickly gets unwieldy, with dozens of lines of exceptions, assertions, property definitions, and decorators that obscure what you actually wrote your code to do. Param lets you focus on the code you're writing, while letting your users know exactly what inputs they can supply. + +The types in Param may remind you of the static types found in some languages, but here the validation is done at runtime and is checking not just types but also numeric ranges or for specific allowed values. Param thus helps you not just with programming correctness, as for static types, but also for validating user inputs. Validating user inputs is generally a large fraction of a program's code, because such inputs are a huge source of vulnerabilities and potential error conditions, and Param lets you avoid ever having to write nearly any of that code. + +The [User Guide](user_guide/index) explains all the other Param features for simplifying your codebase, improving input validation, allowing flexible configuration, and supporting serialization. + +## Using Param for configuration + +Once you have declared your Parameters, they are now fully accessible from Python in a way that helps users of your code configure it and control it if they wish. Without any extra work by the author of the class, a user can use Python to reconfigure any of the defaults that will be used when they use these objects: + +```{code-block} python +>>> A.title = "The sum is" +>>> B.a = 6 + +>>> o3 = B() +>>> o3() +'The sum is: 9' +``` + +Because this configuration is all declarative, the underlying values can come from a YAML file, a JSON blob, URL parameters, CLI arguments, or just about any source, letting you provide users full control over configuration with very little effort. Once you write a Parameterized class, it's up to a user to choose how they want to work with it; your job is done! + +## Using Param to explore parameter spaces + +Param is valuable for _any_ Python codebase, but it offers features that are particularly well suited for running models, simulations, machine learning pipelines, or other programs where the same code needs to be evaluated multiple times to see how it behaves with different parameter values. To facilitate such usage, numeric parameters in Param can be set to a callable value, which will be evaluated every time the parameter is accessed: + +```{code-block} python +>>> import random +>>> o2 = B(a=lambda: random.randint(0,5)) + +>>> o2(), o2(), o2(), o2() +('The sum is: 6', 'The sum is: 7', 'The sum is: 3', 'The sum is: 3') +``` + +The code for `B` doesn't have to have any special knowledge or processing of dynamic values, because accessing `a` always simply returns an integer, not the callable function: + +```{code-block} python +>>> o2.a +4 +``` + +Thus the author of a Parameterized class does not have to take such dynamic values into account; their code simply works with whatever value is returned by the attribute lookup, whether it's dynamic or not. This approach makes Parameterized code immediately ready for exploration across parameter values, whether or not the code's author specifically provided for such usage. + +Param includes a separate and optional module `numbergen` that makes it simple to generate streams of numeric values for use as Parameter values. `numbergen` objects are picklable (unlike a `lambda` as above) and can be combined into expressions to build up parameter sweeps or Monte Carlo simulations: + +```{code-block} python +>>> import numbergen as ng + +>>> o3 = B(a=ng.Choice(choices= [2, 4, 6]), +>>> b = 1 + 2 * ng.UniformRandomInt(ubound=3)) + +>>> o3(), o3(), o3(), o3() +('The sum is: 11', 'The sum is: 3', 'The sum is: 13', 'The sum is: 7') +``` + +Numbergen objects support the usual arithmetic operations like +, -, *, /, //, %, **, and `abs()`, and so they can be freely combined with each other or with mathematical constants. They also optionally respect a global "time" (e.g. a simulation time or a logical counter), which lets you synchronize changes to dynamic values without any special coordination code. + +## Using Param to build GUIs + +Param is useful for any sort of programming, but if you need a GUI with widgets, it turns out that the information captured by a Parameter is very often already what is needed to build such a GUI. For instance, we can use the separate [Panel](https://panel.holoviz.org) library to create widgets in a web browser and display the output from the above class automatically. + +Panel and other GUI libraries can of course explicitly instantiate widgets, so why use Param in this way? Simply put, this approach lets you cleanly separate your domain-specific code, clearly declaring the parameters it requires and respects, from your GUI code. The GUI code controls GUI issues like layout and font size, but the fundamental declaration of what parameters are available is done at the level of the code that actually uses it (classes A and B in this case). With Param, you can _separately_ declare all your Parameters right where they are used, achieving robustness, type checking, and clear documentation, while avoiding having your GUI code be tightly bound up with your domain-specific details. This approach helps you build maintainable, general-purpose codebases that can easily be used with or without GUI interfaces, with unattended batch operation not needing any GUI support and GUIs not needing to be updated every time someone adds a new option or parameter to the underlying code. + +## Learning more + +The [User Guide](user_guide/index) goes through the major features of Param and how to use them. If you are interested in GUI programming, also see the [Param How-to guides](https://panel.holoviz.org/how_to/param/index.html) in Panel, and the rest of the [Panel](https://panel.holoviz.org) docs. Have fun making your life better with Param! diff --git a/_sources/index.md.txt b/_sources/index.md.txt new file mode 100644 index 0000000..54b99e5 --- /dev/null +++ b/_sources/index.md.txt @@ -0,0 +1,34 @@ +# Welcome to Param! + +

+ +Are you a Python programmer? If so, you need Param, and check out our 5-minute intro video to see why! + +
+ + (Download notebook) +
+ +Param is a library for handling all the user-modifiable parameters, arguments, and attributes that control your code. It provides automatic, robust error-checking while dramatically reducing boilerplate code, letting you focus on what you want your code to do rather than on checking for all the possible ways users could supply inappropriate values to a function or class. + +Param lets you program declaratively in Python, stating facts about each of your parameters up front. Once you have done that, Param can handle the rest (type checking, range validation, documentation, serialization, and more!). + +Param-based programs tend to contain much less code than other Python programs, instead just having easily readable and maintainable manifests of Parameters for each object or function. This way your remaining code can be much simpler and clearer, while users can also easily see how to use it properly. Plus, Param doesn't require any code outside of the Python standard library, making it simple to add to any project. + +Param is also useful as a way to keep your domain-specific code independent of any GUI or other user-interface code, letting you maintain a single codebase to support both GUI and non-GUI usage, with the GUI maintainable by UI experts and the domain-specific code maintained by domain experts. + +To quickly see how Param works and can be used, jump straight into the [Getting Started Guide](getting_started), then check out the full functionality in the [User Guide.](user_guide/index) + +```{toctree} +--- +hidden: true +--- +Getting Started +User Guide +Comparisons +API +Releases +Roadmap +Developer Guide +About +``` diff --git a/_sources/reference/index.md.txt b/_sources/reference/index.md.txt new file mode 100644 index 0000000..3139e18 --- /dev/null +++ b/_sources/reference/index.md.txt @@ -0,0 +1,13 @@ +# API reference + +Param effectively installs two packages `param` and `numbergen` importable +under the same names. This section documents their public API. + + +```{toctree} +--- +maxdepth: 2 +--- +Param +Numbergen +``` diff --git a/_sources/reference/numbergen.md.txt b/_sources/reference/numbergen.md.txt new file mode 100644 index 0000000..7083cc4 --- /dev/null +++ b/_sources/reference/numbergen.md.txt @@ -0,0 +1,8 @@ +# Numbergen API reference + +```{eval-rst} +.. automodule:: numbergen + :members: + :inherited-members: + :show-inheritance: +``` diff --git a/_sources/reference/param/generated/param.Action.rst.txt b/_sources/reference/param/generated/param.Action.rst.txt new file mode 100644 index 0000000..7296f8e --- /dev/null +++ b/_sources/reference/param/generated/param.Action.rst.txt @@ -0,0 +1,46 @@ +param.Action +============ + +.. currentmodule:: param + +.. autoclass:: Action + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~Action.__init__ + ~Action.deserialize + ~Action.schema + ~Action.serialize + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~Action.allow_None + ~Action.allow_refs + ~Action.constant + ~Action.default + ~Action.doc + ~Action.instantiate + ~Action.label + ~Action.name + ~Action.nested_refs + ~Action.owner + ~Action.per_instance + ~Action.pickle_default_value + ~Action.precedence + ~Action.readonly + ~Action.rx + ~Action.watchers + + \ No newline at end of file diff --git a/_sources/reference/param/generated/param.Array.rst.txt b/_sources/reference/param/generated/param.Array.rst.txt new file mode 100644 index 0000000..d6b5564 --- /dev/null +++ b/_sources/reference/param/generated/param.Array.rst.txt @@ -0,0 +1,49 @@ +param.Array +=========== + +.. currentmodule:: param + +.. autoclass:: Array + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~Array.__init__ + ~Array.deserialize + ~Array.get_range + ~Array.schema + ~Array.serialize + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~Array.allow_None + ~Array.allow_refs + ~Array.class_ + ~Array.constant + ~Array.default + ~Array.doc + ~Array.instantiate + ~Array.is_instance + ~Array.label + ~Array.name + ~Array.nested_refs + ~Array.owner + ~Array.per_instance + ~Array.pickle_default_value + ~Array.precedence + ~Array.readonly + ~Array.rx + ~Array.watchers + + \ No newline at end of file diff --git a/_sources/reference/param/generated/param.Boolean.rst.txt b/_sources/reference/param/generated/param.Boolean.rst.txt new file mode 100644 index 0000000..ff584a4 --- /dev/null +++ b/_sources/reference/param/generated/param.Boolean.rst.txt @@ -0,0 +1,46 @@ +param.Boolean +============= + +.. currentmodule:: param + +.. autoclass:: Boolean + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~Boolean.__init__ + ~Boolean.deserialize + ~Boolean.schema + ~Boolean.serialize + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~Boolean.allow_None + ~Boolean.allow_refs + ~Boolean.constant + ~Boolean.default + ~Boolean.doc + ~Boolean.instantiate + ~Boolean.label + ~Boolean.name + ~Boolean.nested_refs + ~Boolean.owner + ~Boolean.per_instance + ~Boolean.pickle_default_value + ~Boolean.precedence + ~Boolean.readonly + ~Boolean.rx + ~Boolean.watchers + + \ No newline at end of file diff --git a/_sources/reference/param/generated/param.Bytes.rst.txt b/_sources/reference/param/generated/param.Bytes.rst.txt new file mode 100644 index 0000000..0ced938 --- /dev/null +++ b/_sources/reference/param/generated/param.Bytes.rst.txt @@ -0,0 +1,47 @@ +param.Bytes +=========== + +.. currentmodule:: param + +.. autoclass:: Bytes + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~Bytes.__init__ + ~Bytes.deserialize + ~Bytes.schema + ~Bytes.serialize + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~Bytes.regex + ~Bytes.allow_None + ~Bytes.allow_refs + ~Bytes.constant + ~Bytes.default + ~Bytes.doc + ~Bytes.instantiate + ~Bytes.label + ~Bytes.name + ~Bytes.nested_refs + ~Bytes.owner + ~Bytes.per_instance + ~Bytes.pickle_default_value + ~Bytes.precedence + ~Bytes.readonly + ~Bytes.rx + ~Bytes.watchers + + \ No newline at end of file diff --git a/_sources/reference/param/generated/param.CalendarDateRange.rst.txt b/_sources/reference/param/generated/param.CalendarDateRange.rst.txt new file mode 100644 index 0000000..6880dcc --- /dev/null +++ b/_sources/reference/param/generated/param.CalendarDateRange.rst.txt @@ -0,0 +1,53 @@ +param.CalendarDateRange +======================= + +.. currentmodule:: param + +.. autoclass:: CalendarDateRange + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~CalendarDateRange.__init__ + ~CalendarDateRange.deserialize + ~CalendarDateRange.get_soft_bounds + ~CalendarDateRange.rangestr + ~CalendarDateRange.schema + ~CalendarDateRange.serialize + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~CalendarDateRange.allow_None + ~CalendarDateRange.allow_refs + ~CalendarDateRange.bounds + ~CalendarDateRange.constant + ~CalendarDateRange.default + ~CalendarDateRange.doc + ~CalendarDateRange.inclusive_bounds + ~CalendarDateRange.instantiate + ~CalendarDateRange.label + ~CalendarDateRange.length + ~CalendarDateRange.name + ~CalendarDateRange.nested_refs + ~CalendarDateRange.owner + ~CalendarDateRange.per_instance + ~CalendarDateRange.pickle_default_value + ~CalendarDateRange.precedence + ~CalendarDateRange.readonly + ~CalendarDateRange.rx + ~CalendarDateRange.softbounds + ~CalendarDateRange.step + ~CalendarDateRange.watchers + + \ No newline at end of file diff --git a/_sources/reference/param/generated/param.Callable.rst.txt b/_sources/reference/param/generated/param.Callable.rst.txt new file mode 100644 index 0000000..4092174 --- /dev/null +++ b/_sources/reference/param/generated/param.Callable.rst.txt @@ -0,0 +1,46 @@ +param.Callable +============== + +.. currentmodule:: param + +.. autoclass:: Callable + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~Callable.__init__ + ~Callable.deserialize + ~Callable.schema + ~Callable.serialize + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~Callable.allow_None + ~Callable.allow_refs + ~Callable.constant + ~Callable.default + ~Callable.doc + ~Callable.instantiate + ~Callable.label + ~Callable.name + ~Callable.nested_refs + ~Callable.owner + ~Callable.per_instance + ~Callable.pickle_default_value + ~Callable.precedence + ~Callable.readonly + ~Callable.rx + ~Callable.watchers + + \ No newline at end of file diff --git a/_sources/reference/param/generated/param.ClassSelector.rst.txt b/_sources/reference/param/generated/param.ClassSelector.rst.txt new file mode 100644 index 0000000..d77d1d4 --- /dev/null +++ b/_sources/reference/param/generated/param.ClassSelector.rst.txt @@ -0,0 +1,49 @@ +param.ClassSelector +=================== + +.. currentmodule:: param + +.. autoclass:: ClassSelector + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~ClassSelector.__init__ + ~ClassSelector.deserialize + ~ClassSelector.get_range + ~ClassSelector.schema + ~ClassSelector.serialize + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~ClassSelector.class_ + ~ClassSelector.is_instance + ~ClassSelector.allow_None + ~ClassSelector.allow_refs + ~ClassSelector.constant + ~ClassSelector.default + ~ClassSelector.doc + ~ClassSelector.instantiate + ~ClassSelector.label + ~ClassSelector.name + ~ClassSelector.nested_refs + ~ClassSelector.owner + ~ClassSelector.per_instance + ~ClassSelector.pickle_default_value + ~ClassSelector.precedence + ~ClassSelector.readonly + ~ClassSelector.rx + ~ClassSelector.watchers + + \ No newline at end of file diff --git a/_sources/reference/param/generated/param.Color.rst.txt b/_sources/reference/param/generated/param.Color.rst.txt new file mode 100644 index 0000000..2159f12 --- /dev/null +++ b/_sources/reference/param/generated/param.Color.rst.txt @@ -0,0 +1,47 @@ +param.Color +=========== + +.. currentmodule:: param + +.. autoclass:: Color + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~Color.__init__ + ~Color.deserialize + ~Color.schema + ~Color.serialize + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~Color.allow_named + ~Color.allow_None + ~Color.allow_refs + ~Color.constant + ~Color.default + ~Color.doc + ~Color.instantiate + ~Color.label + ~Color.name + ~Color.nested_refs + ~Color.owner + ~Color.per_instance + ~Color.pickle_default_value + ~Color.precedence + ~Color.readonly + ~Color.rx + ~Color.watchers + + \ No newline at end of file diff --git a/_sources/reference/param/generated/param.Composite.rst.txt b/_sources/reference/param/generated/param.Composite.rst.txt new file mode 100644 index 0000000..eb821d9 --- /dev/null +++ b/_sources/reference/param/generated/param.Composite.rst.txt @@ -0,0 +1,48 @@ +param.Composite +=============== + +.. currentmodule:: param + +.. autoclass:: Composite + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~Composite.__init__ + ~Composite.deserialize + ~Composite.schema + ~Composite.serialize + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~Composite.attribs + ~Composite.objtype + ~Composite.allow_None + ~Composite.allow_refs + ~Composite.constant + ~Composite.default + ~Composite.doc + ~Composite.instantiate + ~Composite.label + ~Composite.name + ~Composite.nested_refs + ~Composite.owner + ~Composite.per_instance + ~Composite.pickle_default_value + ~Composite.precedence + ~Composite.readonly + ~Composite.rx + ~Composite.watchers + + \ No newline at end of file diff --git a/_sources/reference/param/generated/param.DataFrame.rst.txt b/_sources/reference/param/generated/param.DataFrame.rst.txt new file mode 100644 index 0000000..a6367ea --- /dev/null +++ b/_sources/reference/param/generated/param.DataFrame.rst.txt @@ -0,0 +1,52 @@ +param.DataFrame +=============== + +.. currentmodule:: param + +.. autoclass:: DataFrame + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~DataFrame.__init__ + ~DataFrame.deserialize + ~DataFrame.get_range + ~DataFrame.schema + ~DataFrame.serialize + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~DataFrame.rows + ~DataFrame.columns + ~DataFrame.ordered + ~DataFrame.allow_None + ~DataFrame.allow_refs + ~DataFrame.class_ + ~DataFrame.constant + ~DataFrame.default + ~DataFrame.doc + ~DataFrame.instantiate + ~DataFrame.is_instance + ~DataFrame.label + ~DataFrame.name + ~DataFrame.nested_refs + ~DataFrame.owner + ~DataFrame.per_instance + ~DataFrame.pickle_default_value + ~DataFrame.precedence + ~DataFrame.readonly + ~DataFrame.rx + ~DataFrame.watchers + + \ No newline at end of file diff --git a/_sources/reference/param/generated/param.DateRange.rst.txt b/_sources/reference/param/generated/param.DateRange.rst.txt new file mode 100644 index 0000000..0929d9a --- /dev/null +++ b/_sources/reference/param/generated/param.DateRange.rst.txt @@ -0,0 +1,53 @@ +param.DateRange +=============== + +.. currentmodule:: param + +.. autoclass:: DateRange + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~DateRange.__init__ + ~DateRange.deserialize + ~DateRange.get_soft_bounds + ~DateRange.rangestr + ~DateRange.schema + ~DateRange.serialize + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~DateRange.allow_None + ~DateRange.allow_refs + ~DateRange.bounds + ~DateRange.constant + ~DateRange.default + ~DateRange.doc + ~DateRange.inclusive_bounds + ~DateRange.instantiate + ~DateRange.label + ~DateRange.length + ~DateRange.name + ~DateRange.nested_refs + ~DateRange.owner + ~DateRange.per_instance + ~DateRange.pickle_default_value + ~DateRange.precedence + ~DateRange.readonly + ~DateRange.rx + ~DateRange.softbounds + ~DateRange.step + ~DateRange.watchers + + \ No newline at end of file diff --git a/_sources/reference/param/generated/param.Dict.rst.txt b/_sources/reference/param/generated/param.Dict.rst.txt new file mode 100644 index 0000000..7af4cf1 --- /dev/null +++ b/_sources/reference/param/generated/param.Dict.rst.txt @@ -0,0 +1,49 @@ +param.Dict +========== + +.. currentmodule:: param + +.. autoclass:: Dict + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~Dict.__init__ + ~Dict.deserialize + ~Dict.get_range + ~Dict.schema + ~Dict.serialize + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~Dict.allow_None + ~Dict.allow_refs + ~Dict.class_ + ~Dict.constant + ~Dict.default + ~Dict.doc + ~Dict.instantiate + ~Dict.is_instance + ~Dict.label + ~Dict.name + ~Dict.nested_refs + ~Dict.owner + ~Dict.per_instance + ~Dict.pickle_default_value + ~Dict.precedence + ~Dict.readonly + ~Dict.rx + ~Dict.watchers + + \ No newline at end of file diff --git a/_sources/reference/param/generated/param.Dynamic.rst.txt b/_sources/reference/param/generated/param.Dynamic.rst.txt new file mode 100644 index 0000000..4add44b --- /dev/null +++ b/_sources/reference/param/generated/param.Dynamic.rst.txt @@ -0,0 +1,48 @@ +param.Dynamic +============= + +.. currentmodule:: param + +.. autoclass:: Dynamic + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~Dynamic.__init__ + ~Dynamic.deserialize + ~Dynamic.schema + ~Dynamic.serialize + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~Dynamic.allow_None + ~Dynamic.allow_refs + ~Dynamic.constant + ~Dynamic.default + ~Dynamic.doc + ~Dynamic.instantiate + ~Dynamic.label + ~Dynamic.name + ~Dynamic.nested_refs + ~Dynamic.owner + ~Dynamic.per_instance + ~Dynamic.pickle_default_value + ~Dynamic.precedence + ~Dynamic.readonly + ~Dynamic.rx + ~Dynamic.time_dependent + ~Dynamic.time_fn + ~Dynamic.watchers + + \ No newline at end of file diff --git a/_sources/reference/param/generated/param.Event.rst.txt b/_sources/reference/param/generated/param.Event.rst.txt new file mode 100644 index 0000000..bbb3f29 --- /dev/null +++ b/_sources/reference/param/generated/param.Event.rst.txt @@ -0,0 +1,46 @@ +param.Event +=========== + +.. currentmodule:: param + +.. autoclass:: Event + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~Event.__init__ + ~Event.deserialize + ~Event.schema + ~Event.serialize + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~Event.allow_None + ~Event.allow_refs + ~Event.constant + ~Event.default + ~Event.doc + ~Event.instantiate + ~Event.label + ~Event.name + ~Event.nested_refs + ~Event.owner + ~Event.per_instance + ~Event.pickle_default_value + ~Event.precedence + ~Event.readonly + ~Event.rx + ~Event.watchers + + \ No newline at end of file diff --git a/_sources/reference/param/generated/param.FileSelector.rst.txt b/_sources/reference/param/generated/param.FileSelector.rst.txt new file mode 100644 index 0000000..52266a2 --- /dev/null +++ b/_sources/reference/param/generated/param.FileSelector.rst.txt @@ -0,0 +1,54 @@ +param.FileSelector +================== + +.. currentmodule:: param + +.. autoclass:: FileSelector + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~FileSelector.__init__ + ~FileSelector.compute_default + ~FileSelector.deserialize + ~FileSelector.get_range + ~FileSelector.schema + ~FileSelector.serialize + ~FileSelector.update + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~FileSelector.path + ~FileSelector.allow_None + ~FileSelector.allow_refs + ~FileSelector.check_on_set + ~FileSelector.compute_default_fn + ~FileSelector.constant + ~FileSelector.default + ~FileSelector.doc + ~FileSelector.instantiate + ~FileSelector.label + ~FileSelector.name + ~FileSelector.names + ~FileSelector.nested_refs + ~FileSelector.objects + ~FileSelector.owner + ~FileSelector.per_instance + ~FileSelector.pickle_default_value + ~FileSelector.precedence + ~FileSelector.readonly + ~FileSelector.rx + ~FileSelector.watchers + + \ No newline at end of file diff --git a/_sources/reference/param/generated/param.Filename.rst.txt b/_sources/reference/param/generated/param.Filename.rst.txt new file mode 100644 index 0000000..092378f --- /dev/null +++ b/_sources/reference/param/generated/param.Filename.rst.txt @@ -0,0 +1,48 @@ +param.Filename +============== + +.. currentmodule:: param + +.. autoclass:: Filename + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~Filename.__init__ + ~Filename.deserialize + ~Filename.schema + ~Filename.serialize + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~Filename.allow_None + ~Filename.allow_refs + ~Filename.check_exists + ~Filename.constant + ~Filename.default + ~Filename.doc + ~Filename.instantiate + ~Filename.label + ~Filename.name + ~Filename.nested_refs + ~Filename.owner + ~Filename.per_instance + ~Filename.pickle_default_value + ~Filename.precedence + ~Filename.readonly + ~Filename.rx + ~Filename.search_paths + ~Filename.watchers + + \ No newline at end of file diff --git a/_sources/reference/param/generated/param.Foldername.rst.txt b/_sources/reference/param/generated/param.Foldername.rst.txt new file mode 100644 index 0000000..b57c67d --- /dev/null +++ b/_sources/reference/param/generated/param.Foldername.rst.txt @@ -0,0 +1,48 @@ +param.Foldername +================ + +.. currentmodule:: param + +.. autoclass:: Foldername + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~Foldername.__init__ + ~Foldername.deserialize + ~Foldername.schema + ~Foldername.serialize + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~Foldername.allow_None + ~Foldername.allow_refs + ~Foldername.check_exists + ~Foldername.constant + ~Foldername.default + ~Foldername.doc + ~Foldername.instantiate + ~Foldername.label + ~Foldername.name + ~Foldername.nested_refs + ~Foldername.owner + ~Foldername.per_instance + ~Foldername.pickle_default_value + ~Foldername.precedence + ~Foldername.readonly + ~Foldername.rx + ~Foldername.search_paths + ~Foldername.watchers + + \ No newline at end of file diff --git a/_sources/reference/param/generated/param.HookList.rst.txt b/_sources/reference/param/generated/param.HookList.rst.txt new file mode 100644 index 0000000..07b42de --- /dev/null +++ b/_sources/reference/param/generated/param.HookList.rst.txt @@ -0,0 +1,49 @@ +param.HookList +============== + +.. currentmodule:: param + +.. autoclass:: HookList + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~HookList.__init__ + ~HookList.deserialize + ~HookList.schema + ~HookList.serialize + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~HookList.class_ + ~HookList.bounds + ~HookList.allow_None + ~HookList.allow_refs + ~HookList.constant + ~HookList.default + ~HookList.doc + ~HookList.instantiate + ~HookList.item_type + ~HookList.label + ~HookList.name + ~HookList.nested_refs + ~HookList.owner + ~HookList.per_instance + ~HookList.pickle_default_value + ~HookList.precedence + ~HookList.readonly + ~HookList.rx + ~HookList.watchers + + \ No newline at end of file diff --git a/_sources/reference/param/generated/param.Integer.rst.txt b/_sources/reference/param/generated/param.Integer.rst.txt new file mode 100644 index 0000000..8fb8638 --- /dev/null +++ b/_sources/reference/param/generated/param.Integer.rst.txt @@ -0,0 +1,56 @@ +param.Integer +============= + +.. currentmodule:: param + +.. autoclass:: Integer + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~Integer.__init__ + ~Integer.crop_to_bounds + ~Integer.deserialize + ~Integer.get_soft_bounds + ~Integer.schema + ~Integer.serialize + ~Integer.set_in_bounds + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~Integer.allow_None + ~Integer.allow_refs + ~Integer.bounds + ~Integer.constant + ~Integer.default + ~Integer.doc + ~Integer.inclusive_bounds + ~Integer.instantiate + ~Integer.label + ~Integer.name + ~Integer.nested_refs + ~Integer.owner + ~Integer.per_instance + ~Integer.pickle_default_value + ~Integer.precedence + ~Integer.readonly + ~Integer.rx + ~Integer.set_hook + ~Integer.softbounds + ~Integer.step + ~Integer.time_dependent + ~Integer.time_fn + ~Integer.watchers + + \ No newline at end of file diff --git a/_sources/reference/param/generated/param.List.rst.txt b/_sources/reference/param/generated/param.List.rst.txt new file mode 100644 index 0000000..946535e --- /dev/null +++ b/_sources/reference/param/generated/param.List.rst.txt @@ -0,0 +1,49 @@ +param.List +========== + +.. currentmodule:: param + +.. autoclass:: List + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~List.__init__ + ~List.deserialize + ~List.schema + ~List.serialize + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~List.bounds + ~List.item_type + ~List.class_ + ~List.allow_None + ~List.allow_refs + ~List.constant + ~List.default + ~List.doc + ~List.instantiate + ~List.label + ~List.name + ~List.nested_refs + ~List.owner + ~List.per_instance + ~List.pickle_default_value + ~List.precedence + ~List.readonly + ~List.rx + ~List.watchers + + \ No newline at end of file diff --git a/_sources/reference/param/generated/param.ListSelector.rst.txt b/_sources/reference/param/generated/param.ListSelector.rst.txt new file mode 100644 index 0000000..3caa1ed --- /dev/null +++ b/_sources/reference/param/generated/param.ListSelector.rst.txt @@ -0,0 +1,52 @@ +param.ListSelector +================== + +.. currentmodule:: param + +.. autoclass:: ListSelector + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~ListSelector.__init__ + ~ListSelector.compute_default + ~ListSelector.deserialize + ~ListSelector.get_range + ~ListSelector.schema + ~ListSelector.serialize + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~ListSelector.allow_None + ~ListSelector.allow_refs + ~ListSelector.check_on_set + ~ListSelector.compute_default_fn + ~ListSelector.constant + ~ListSelector.default + ~ListSelector.doc + ~ListSelector.instantiate + ~ListSelector.label + ~ListSelector.name + ~ListSelector.names + ~ListSelector.nested_refs + ~ListSelector.objects + ~ListSelector.owner + ~ListSelector.per_instance + ~ListSelector.pickle_default_value + ~ListSelector.precedence + ~ListSelector.readonly + ~ListSelector.rx + ~ListSelector.watchers + + \ No newline at end of file diff --git a/_sources/reference/param/generated/param.Magnitude.rst.txt b/_sources/reference/param/generated/param.Magnitude.rst.txt new file mode 100644 index 0000000..847f007 --- /dev/null +++ b/_sources/reference/param/generated/param.Magnitude.rst.txt @@ -0,0 +1,56 @@ +param.Magnitude +=============== + +.. currentmodule:: param + +.. autoclass:: Magnitude + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~Magnitude.__init__ + ~Magnitude.crop_to_bounds + ~Magnitude.deserialize + ~Magnitude.get_soft_bounds + ~Magnitude.schema + ~Magnitude.serialize + ~Magnitude.set_in_bounds + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~Magnitude.allow_None + ~Magnitude.allow_refs + ~Magnitude.bounds + ~Magnitude.constant + ~Magnitude.default + ~Magnitude.doc + ~Magnitude.inclusive_bounds + ~Magnitude.instantiate + ~Magnitude.label + ~Magnitude.name + ~Magnitude.nested_refs + ~Magnitude.owner + ~Magnitude.per_instance + ~Magnitude.pickle_default_value + ~Magnitude.precedence + ~Magnitude.readonly + ~Magnitude.rx + ~Magnitude.set_hook + ~Magnitude.softbounds + ~Magnitude.step + ~Magnitude.time_dependent + ~Magnitude.time_fn + ~Magnitude.watchers + + \ No newline at end of file diff --git a/_sources/reference/param/generated/param.MultiFileSelector.rst.txt b/_sources/reference/param/generated/param.MultiFileSelector.rst.txt new file mode 100644 index 0000000..26daaa0 --- /dev/null +++ b/_sources/reference/param/generated/param.MultiFileSelector.rst.txt @@ -0,0 +1,54 @@ +param.MultiFileSelector +======================= + +.. currentmodule:: param + +.. autoclass:: MultiFileSelector + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~MultiFileSelector.__init__ + ~MultiFileSelector.compute_default + ~MultiFileSelector.deserialize + ~MultiFileSelector.get_range + ~MultiFileSelector.schema + ~MultiFileSelector.serialize + ~MultiFileSelector.update + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~MultiFileSelector.path + ~MultiFileSelector.allow_None + ~MultiFileSelector.allow_refs + ~MultiFileSelector.check_on_set + ~MultiFileSelector.compute_default_fn + ~MultiFileSelector.constant + ~MultiFileSelector.default + ~MultiFileSelector.doc + ~MultiFileSelector.instantiate + ~MultiFileSelector.label + ~MultiFileSelector.name + ~MultiFileSelector.names + ~MultiFileSelector.nested_refs + ~MultiFileSelector.objects + ~MultiFileSelector.owner + ~MultiFileSelector.per_instance + ~MultiFileSelector.pickle_default_value + ~MultiFileSelector.precedence + ~MultiFileSelector.readonly + ~MultiFileSelector.rx + ~MultiFileSelector.watchers + + \ No newline at end of file diff --git a/_sources/reference/param/generated/param.Number.rst.txt b/_sources/reference/param/generated/param.Number.rst.txt new file mode 100644 index 0000000..4688d6a --- /dev/null +++ b/_sources/reference/param/generated/param.Number.rst.txt @@ -0,0 +1,56 @@ +param.Number +============ + +.. currentmodule:: param + +.. autoclass:: Number + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~Number.__init__ + ~Number.crop_to_bounds + ~Number.deserialize + ~Number.get_soft_bounds + ~Number.schema + ~Number.serialize + ~Number.set_in_bounds + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~Number.bounds + ~Number.softbounds + ~Number.inclusive_bounds + ~Number.set_hook + ~Number.step + ~Number.allow_None + ~Number.allow_refs + ~Number.constant + ~Number.default + ~Number.doc + ~Number.instantiate + ~Number.label + ~Number.name + ~Number.nested_refs + ~Number.owner + ~Number.per_instance + ~Number.pickle_default_value + ~Number.precedence + ~Number.readonly + ~Number.rx + ~Number.time_dependent + ~Number.time_fn + ~Number.watchers + + \ No newline at end of file diff --git a/_sources/reference/param/generated/param.NumericTuple.rst.txt b/_sources/reference/param/generated/param.NumericTuple.rst.txt new file mode 100644 index 0000000..681b21d --- /dev/null +++ b/_sources/reference/param/generated/param.NumericTuple.rst.txt @@ -0,0 +1,47 @@ +param.NumericTuple +================== + +.. currentmodule:: param + +.. autoclass:: NumericTuple + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~NumericTuple.__init__ + ~NumericTuple.deserialize + ~NumericTuple.schema + ~NumericTuple.serialize + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~NumericTuple.allow_None + ~NumericTuple.allow_refs + ~NumericTuple.constant + ~NumericTuple.default + ~NumericTuple.doc + ~NumericTuple.instantiate + ~NumericTuple.label + ~NumericTuple.length + ~NumericTuple.name + ~NumericTuple.nested_refs + ~NumericTuple.owner + ~NumericTuple.per_instance + ~NumericTuple.pickle_default_value + ~NumericTuple.precedence + ~NumericTuple.readonly + ~NumericTuple.rx + ~NumericTuple.watchers + + \ No newline at end of file diff --git a/_sources/reference/param/generated/param.ParamOverrides.rst.txt b/_sources/reference/param/generated/param.ParamOverrides.rst.txt new file mode 100644 index 0000000..437e02c --- /dev/null +++ b/_sources/reference/param/generated/param.ParamOverrides.rst.txt @@ -0,0 +1,35 @@ +param.ParamOverrides +==================== + +.. currentmodule:: param + +.. autoclass:: ParamOverrides + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~ParamOverrides.__init__ + ~ParamOverrides.clear + ~ParamOverrides.copy + ~ParamOverrides.extra_keywords + ~ParamOverrides.fromkeys + ~ParamOverrides.get + ~ParamOverrides.items + ~ParamOverrides.keys + ~ParamOverrides.param_keywords + ~ParamOverrides.pop + ~ParamOverrides.popitem + ~ParamOverrides.setdefault + ~ParamOverrides.update + ~ParamOverrides.values + + + + + + \ No newline at end of file diff --git a/_sources/reference/param/generated/param.Parameter.rst.txt b/_sources/reference/param/generated/param.Parameter.rst.txt new file mode 100644 index 0000000..61c6abc --- /dev/null +++ b/_sources/reference/param/generated/param.Parameter.rst.txt @@ -0,0 +1,46 @@ +param.Parameter +=============== + +.. currentmodule:: param + +.. autoclass:: Parameter + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~Parameter.__init__ + ~Parameter.deserialize + ~Parameter.schema + ~Parameter.serialize + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~Parameter.name + ~Parameter.default + ~Parameter.doc + ~Parameter.precedence + ~Parameter.instantiate + ~Parameter.constant + ~Parameter.readonly + ~Parameter.pickle_default_value + ~Parameter.allow_None + ~Parameter.per_instance + ~Parameter.watchers + ~Parameter.owner + ~Parameter.allow_refs + ~Parameter.nested_refs + ~Parameter.label + ~Parameter.rx + + \ No newline at end of file diff --git a/_sources/reference/param/generated/param.Parameterized.rst.txt b/_sources/reference/param/generated/param.Parameterized.rst.txt new file mode 100644 index 0000000..1eed5f5 --- /dev/null +++ b/_sources/reference/param/generated/param.Parameterized.rst.txt @@ -0,0 +1,29 @@ +param.Parameterized +=================== + +.. currentmodule:: param + +.. autoclass:: Parameterized + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~Parameterized.__init__ + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~Parameterized.name + ~Parameterized.param + + \ No newline at end of file diff --git a/_sources/reference/param/generated/param.ParameterizedFunction.rst.txt b/_sources/reference/param/generated/param.ParameterizedFunction.rst.txt new file mode 100644 index 0000000..1261abb --- /dev/null +++ b/_sources/reference/param/generated/param.ParameterizedFunction.rst.txt @@ -0,0 +1,30 @@ +param.ParameterizedFunction +=========================== + +.. currentmodule:: param + +.. autoclass:: ParameterizedFunction + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~ParameterizedFunction.__init__ + ~ParameterizedFunction.instance + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~ParameterizedFunction.name + ~ParameterizedFunction.param + + \ No newline at end of file diff --git a/_sources/reference/param/generated/param.Path.rst.txt b/_sources/reference/param/generated/param.Path.rst.txt new file mode 100644 index 0000000..5e39999 --- /dev/null +++ b/_sources/reference/param/generated/param.Path.rst.txt @@ -0,0 +1,48 @@ +param.Path +========== + +.. currentmodule:: param + +.. autoclass:: Path + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~Path.__init__ + ~Path.deserialize + ~Path.schema + ~Path.serialize + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~Path.search_paths + ~Path.check_exists + ~Path.allow_None + ~Path.allow_refs + ~Path.constant + ~Path.default + ~Path.doc + ~Path.instantiate + ~Path.label + ~Path.name + ~Path.nested_refs + ~Path.owner + ~Path.per_instance + ~Path.pickle_default_value + ~Path.precedence + ~Path.readonly + ~Path.rx + ~Path.watchers + + \ No newline at end of file diff --git a/_sources/reference/param/generated/param.Range.rst.txt b/_sources/reference/param/generated/param.Range.rst.txt new file mode 100644 index 0000000..1eee3ee --- /dev/null +++ b/_sources/reference/param/generated/param.Range.rst.txt @@ -0,0 +1,53 @@ +param.Range +=========== + +.. currentmodule:: param + +.. autoclass:: Range + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~Range.__init__ + ~Range.deserialize + ~Range.get_soft_bounds + ~Range.rangestr + ~Range.schema + ~Range.serialize + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~Range.bounds + ~Range.inclusive_bounds + ~Range.softbounds + ~Range.step + ~Range.allow_None + ~Range.allow_refs + ~Range.constant + ~Range.default + ~Range.doc + ~Range.instantiate + ~Range.label + ~Range.length + ~Range.name + ~Range.nested_refs + ~Range.owner + ~Range.per_instance + ~Range.pickle_default_value + ~Range.precedence + ~Range.readonly + ~Range.rx + ~Range.watchers + + \ No newline at end of file diff --git a/_sources/reference/param/generated/param.Selector.rst.txt b/_sources/reference/param/generated/param.Selector.rst.txt new file mode 100644 index 0000000..a80b889 --- /dev/null +++ b/_sources/reference/param/generated/param.Selector.rst.txt @@ -0,0 +1,52 @@ +param.Selector +============== + +.. currentmodule:: param + +.. autoclass:: Selector + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~Selector.__init__ + ~Selector.compute_default + ~Selector.deserialize + ~Selector.get_range + ~Selector.schema + ~Selector.serialize + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~Selector.compute_default_fn + ~Selector.check_on_set + ~Selector.names + ~Selector.allow_None + ~Selector.allow_refs + ~Selector.constant + ~Selector.default + ~Selector.doc + ~Selector.instantiate + ~Selector.label + ~Selector.name + ~Selector.nested_refs + ~Selector.objects + ~Selector.owner + ~Selector.per_instance + ~Selector.pickle_default_value + ~Selector.precedence + ~Selector.readonly + ~Selector.rx + ~Selector.watchers + + \ No newline at end of file diff --git a/_sources/reference/param/generated/param.Series.rst.txt b/_sources/reference/param/generated/param.Series.rst.txt new file mode 100644 index 0000000..02de699 --- /dev/null +++ b/_sources/reference/param/generated/param.Series.rst.txt @@ -0,0 +1,50 @@ +param.Series +============ + +.. currentmodule:: param + +.. autoclass:: Series + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~Series.__init__ + ~Series.deserialize + ~Series.get_range + ~Series.schema + ~Series.serialize + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~Series.rows + ~Series.allow_None + ~Series.allow_refs + ~Series.class_ + ~Series.constant + ~Series.default + ~Series.doc + ~Series.instantiate + ~Series.is_instance + ~Series.label + ~Series.name + ~Series.nested_refs + ~Series.owner + ~Series.per_instance + ~Series.pickle_default_value + ~Series.precedence + ~Series.readonly + ~Series.rx + ~Series.watchers + + \ No newline at end of file diff --git a/_sources/reference/param/generated/param.String.rst.txt b/_sources/reference/param/generated/param.String.rst.txt new file mode 100644 index 0000000..309afc7 --- /dev/null +++ b/_sources/reference/param/generated/param.String.rst.txt @@ -0,0 +1,47 @@ +param.String +============ + +.. currentmodule:: param + +.. autoclass:: String + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~String.__init__ + ~String.deserialize + ~String.schema + ~String.serialize + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~String.regex + ~String.allow_None + ~String.allow_refs + ~String.constant + ~String.default + ~String.doc + ~String.instantiate + ~String.label + ~String.name + ~String.nested_refs + ~String.owner + ~String.per_instance + ~String.pickle_default_value + ~String.precedence + ~String.readonly + ~String.rx + ~String.watchers + + \ No newline at end of file diff --git a/_sources/reference/param/generated/param.Tuple.rst.txt b/_sources/reference/param/generated/param.Tuple.rst.txt new file mode 100644 index 0000000..17364be --- /dev/null +++ b/_sources/reference/param/generated/param.Tuple.rst.txt @@ -0,0 +1,47 @@ +param.Tuple +=========== + +.. currentmodule:: param + +.. autoclass:: Tuple + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~Tuple.__init__ + ~Tuple.deserialize + ~Tuple.schema + ~Tuple.serialize + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~Tuple.length + ~Tuple.allow_None + ~Tuple.allow_refs + ~Tuple.constant + ~Tuple.default + ~Tuple.doc + ~Tuple.instantiate + ~Tuple.label + ~Tuple.name + ~Tuple.nested_refs + ~Tuple.owner + ~Tuple.per_instance + ~Tuple.pickle_default_value + ~Tuple.precedence + ~Tuple.readonly + ~Tuple.rx + ~Tuple.watchers + + \ No newline at end of file diff --git a/_sources/reference/param/generated/param.XYCoordinates.rst.txt b/_sources/reference/param/generated/param.XYCoordinates.rst.txt new file mode 100644 index 0000000..d929983 --- /dev/null +++ b/_sources/reference/param/generated/param.XYCoordinates.rst.txt @@ -0,0 +1,47 @@ +param.XYCoordinates +=================== + +.. currentmodule:: param + +.. autoclass:: XYCoordinates + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~XYCoordinates.__init__ + ~XYCoordinates.deserialize + ~XYCoordinates.schema + ~XYCoordinates.serialize + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~XYCoordinates.allow_None + ~XYCoordinates.allow_refs + ~XYCoordinates.constant + ~XYCoordinates.default + ~XYCoordinates.doc + ~XYCoordinates.instantiate + ~XYCoordinates.label + ~XYCoordinates.length + ~XYCoordinates.name + ~XYCoordinates.nested_refs + ~XYCoordinates.owner + ~XYCoordinates.per_instance + ~XYCoordinates.pickle_default_value + ~XYCoordinates.precedence + ~XYCoordinates.readonly + ~XYCoordinates.rx + ~XYCoordinates.watchers + + \ No newline at end of file diff --git a/_sources/reference/param/generated/param.batch_watch.rst.txt b/_sources/reference/param/generated/param.batch_watch.rst.txt new file mode 100644 index 0000000..fce4dc9 --- /dev/null +++ b/_sources/reference/param/generated/param.batch_watch.rst.txt @@ -0,0 +1,6 @@ +param.batch\_watch +================== + +.. currentmodule:: param + +.. autofunction:: batch_watch \ No newline at end of file diff --git a/_sources/reference/param/generated/param.concrete_descendents.rst.txt b/_sources/reference/param/generated/param.concrete_descendents.rst.txt new file mode 100644 index 0000000..2b11b0d --- /dev/null +++ b/_sources/reference/param/generated/param.concrete_descendents.rst.txt @@ -0,0 +1,6 @@ +param.concrete\_descendents +=========================== + +.. currentmodule:: param + +.. autofunction:: concrete_descendents \ No newline at end of file diff --git a/_sources/reference/param/generated/param.depends.rst.txt b/_sources/reference/param/generated/param.depends.rst.txt new file mode 100644 index 0000000..9908bce --- /dev/null +++ b/_sources/reference/param/generated/param.depends.rst.txt @@ -0,0 +1,6 @@ +param.depends +============= + +.. currentmodule:: param + +.. autofunction:: depends \ No newline at end of file diff --git a/_sources/reference/param/generated/param.discard_events.rst.txt b/_sources/reference/param/generated/param.discard_events.rst.txt new file mode 100644 index 0000000..00d31da --- /dev/null +++ b/_sources/reference/param/generated/param.discard_events.rst.txt @@ -0,0 +1,6 @@ +param.discard\_events +===================== + +.. currentmodule:: param + +.. autofunction:: discard_events \ No newline at end of file diff --git a/_sources/reference/param/generated/param.edit_constant.rst.txt b/_sources/reference/param/generated/param.edit_constant.rst.txt new file mode 100644 index 0000000..41ef146 --- /dev/null +++ b/_sources/reference/param/generated/param.edit_constant.rst.txt @@ -0,0 +1,6 @@ +param.edit\_constant +==================== + +.. currentmodule:: param + +.. autofunction:: edit_constant \ No newline at end of file diff --git a/_sources/reference/param/generated/param.get_soft_bounds.rst.txt b/_sources/reference/param/generated/param.get_soft_bounds.rst.txt new file mode 100644 index 0000000..0c55bf4 --- /dev/null +++ b/_sources/reference/param/generated/param.get_soft_bounds.rst.txt @@ -0,0 +1,6 @@ +param.get\_soft\_bounds +======================= + +.. currentmodule:: param + +.. autofunction:: get_soft_bounds \ No newline at end of file diff --git a/_sources/reference/param/generated/param.guess_bounds.rst.txt b/_sources/reference/param/generated/param.guess_bounds.rst.txt new file mode 100644 index 0000000..4062c0f --- /dev/null +++ b/_sources/reference/param/generated/param.guess_bounds.rst.txt @@ -0,0 +1,6 @@ +param.guess\_bounds +=================== + +.. currentmodule:: param + +.. autofunction:: guess_bounds \ No newline at end of file diff --git a/_sources/reference/param/generated/param.guess_param_types.rst.txt b/_sources/reference/param/generated/param.guess_param_types.rst.txt new file mode 100644 index 0000000..acfcfe5 --- /dev/null +++ b/_sources/reference/param/generated/param.guess_param_types.rst.txt @@ -0,0 +1,6 @@ +param.guess\_param\_types +========================= + +.. currentmodule:: param + +.. autofunction:: guess_param_types \ No newline at end of file diff --git a/_sources/reference/param/generated/param.output.rst.txt b/_sources/reference/param/generated/param.output.rst.txt new file mode 100644 index 0000000..e3f3340 --- /dev/null +++ b/_sources/reference/param/generated/param.output.rst.txt @@ -0,0 +1,6 @@ +param.output +============ + +.. currentmodule:: param + +.. autofunction:: output \ No newline at end of file diff --git a/_sources/reference/param/generated/param.param_union.rst.txt b/_sources/reference/param/generated/param.param_union.rst.txt new file mode 100644 index 0000000..a6aaea2 --- /dev/null +++ b/_sources/reference/param/generated/param.param_union.rst.txt @@ -0,0 +1,6 @@ +param.param\_union +================== + +.. currentmodule:: param + +.. autofunction:: param_union \ No newline at end of file diff --git a/_sources/reference/param/generated/param.parameterized.Event.rst.txt b/_sources/reference/param/generated/param.parameterized.Event.rst.txt new file mode 100644 index 0000000..f26a7e8 --- /dev/null +++ b/_sources/reference/param/generated/param.parameterized.Event.rst.txt @@ -0,0 +1,36 @@ +param.parameterized.Event +========================= + +.. currentmodule:: param.parameterized + +.. autoclass:: Event + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~Event.__init__ + ~Event.count + ~Event.index + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~Event.cls + ~Event.name + ~Event.new + ~Event.obj + ~Event.old + ~Event.type + ~Event.what + + \ No newline at end of file diff --git a/_sources/reference/param/generated/param.parameterized.Parameters.add_parameter.rst.txt b/_sources/reference/param/generated/param.parameterized.Parameters.add_parameter.rst.txt new file mode 100644 index 0000000..c2d232e --- /dev/null +++ b/_sources/reference/param/generated/param.parameterized.Parameters.add_parameter.rst.txt @@ -0,0 +1,6 @@ +param.parameterized.Parameters.add\_parameter +============================================= + +.. currentmodule:: param.parameterized + +.. automethod:: Parameters.add_parameter \ No newline at end of file diff --git a/_sources/reference/param/generated/param.parameterized.Parameters.debug.rst.txt b/_sources/reference/param/generated/param.parameterized.Parameters.debug.rst.txt new file mode 100644 index 0000000..53e5739 --- /dev/null +++ b/_sources/reference/param/generated/param.parameterized.Parameters.debug.rst.txt @@ -0,0 +1,6 @@ +param.parameterized.Parameters.debug +==================================== + +.. currentmodule:: param.parameterized + +.. automethod:: Parameters.debug \ No newline at end of file diff --git a/_sources/reference/param/generated/param.parameterized.Parameters.defaults.rst.txt b/_sources/reference/param/generated/param.parameterized.Parameters.defaults.rst.txt new file mode 100644 index 0000000..fb87b10 --- /dev/null +++ b/_sources/reference/param/generated/param.parameterized.Parameters.defaults.rst.txt @@ -0,0 +1,6 @@ +param.parameterized.Parameters.defaults +======================================= + +.. currentmodule:: param.parameterized + +.. automethod:: Parameters.defaults \ No newline at end of file diff --git a/_sources/reference/param/generated/param.parameterized.Parameters.deserialize_parameters.rst.txt b/_sources/reference/param/generated/param.parameterized.Parameters.deserialize_parameters.rst.txt new file mode 100644 index 0000000..073b480 --- /dev/null +++ b/_sources/reference/param/generated/param.parameterized.Parameters.deserialize_parameters.rst.txt @@ -0,0 +1,6 @@ +param.parameterized.Parameters.deserialize\_parameters +====================================================== + +.. currentmodule:: param.parameterized + +.. automethod:: Parameters.deserialize_parameters \ No newline at end of file diff --git a/_sources/reference/param/generated/param.parameterized.Parameters.deserialize_value.rst.txt b/_sources/reference/param/generated/param.parameterized.Parameters.deserialize_value.rst.txt new file mode 100644 index 0000000..9cc79b7 --- /dev/null +++ b/_sources/reference/param/generated/param.parameterized.Parameters.deserialize_value.rst.txt @@ -0,0 +1,6 @@ +param.parameterized.Parameters.deserialize\_value +================================================= + +.. currentmodule:: param.parameterized + +.. automethod:: Parameters.deserialize_value \ No newline at end of file diff --git a/_sources/reference/param/generated/param.parameterized.Parameters.force_new_dynamic_value.rst.txt b/_sources/reference/param/generated/param.parameterized.Parameters.force_new_dynamic_value.rst.txt new file mode 100644 index 0000000..140c10f --- /dev/null +++ b/_sources/reference/param/generated/param.parameterized.Parameters.force_new_dynamic_value.rst.txt @@ -0,0 +1,6 @@ +param.parameterized.Parameters.force\_new\_dynamic\_value +========================================================= + +.. currentmodule:: param.parameterized + +.. automethod:: Parameters.force_new_dynamic_value \ No newline at end of file diff --git a/_sources/reference/param/generated/param.parameterized.Parameters.get_param_values.rst.txt b/_sources/reference/param/generated/param.parameterized.Parameters.get_param_values.rst.txt new file mode 100644 index 0000000..ea5a465 --- /dev/null +++ b/_sources/reference/param/generated/param.parameterized.Parameters.get_param_values.rst.txt @@ -0,0 +1,6 @@ +param.parameterized.Parameters.get\_param\_values +================================================= + +.. currentmodule:: param.parameterized + +.. automethod:: Parameters.get_param_values \ No newline at end of file diff --git a/_sources/reference/param/generated/param.parameterized.Parameters.get_value_generator.rst.txt b/_sources/reference/param/generated/param.parameterized.Parameters.get_value_generator.rst.txt new file mode 100644 index 0000000..239e79a --- /dev/null +++ b/_sources/reference/param/generated/param.parameterized.Parameters.get_value_generator.rst.txt @@ -0,0 +1,6 @@ +param.parameterized.Parameters.get\_value\_generator +==================================================== + +.. currentmodule:: param.parameterized + +.. automethod:: Parameters.get_value_generator \ No newline at end of file diff --git a/_sources/reference/param/generated/param.parameterized.Parameters.inspect_value.rst.txt b/_sources/reference/param/generated/param.parameterized.Parameters.inspect_value.rst.txt new file mode 100644 index 0000000..13375b3 --- /dev/null +++ b/_sources/reference/param/generated/param.parameterized.Parameters.inspect_value.rst.txt @@ -0,0 +1,6 @@ +param.parameterized.Parameters.inspect\_value +============================================= + +.. currentmodule:: param.parameterized + +.. automethod:: Parameters.inspect_value \ No newline at end of file diff --git a/_sources/reference/param/generated/param.parameterized.Parameters.log.rst.txt b/_sources/reference/param/generated/param.parameterized.Parameters.log.rst.txt new file mode 100644 index 0000000..fc06d76 --- /dev/null +++ b/_sources/reference/param/generated/param.parameterized.Parameters.log.rst.txt @@ -0,0 +1,6 @@ +param.parameterized.Parameters.log +================================== + +.. currentmodule:: param.parameterized + +.. automethod:: Parameters.log \ No newline at end of file diff --git a/_sources/reference/param/generated/param.parameterized.Parameters.message.rst.txt b/_sources/reference/param/generated/param.parameterized.Parameters.message.rst.txt new file mode 100644 index 0000000..025cebc --- /dev/null +++ b/_sources/reference/param/generated/param.parameterized.Parameters.message.rst.txt @@ -0,0 +1,6 @@ +param.parameterized.Parameters.message +====================================== + +.. currentmodule:: param.parameterized + +.. automethod:: Parameters.message \ No newline at end of file diff --git a/_sources/reference/param/generated/param.parameterized.Parameters.method_dependencies.rst.txt b/_sources/reference/param/generated/param.parameterized.Parameters.method_dependencies.rst.txt new file mode 100644 index 0000000..eac931a --- /dev/null +++ b/_sources/reference/param/generated/param.parameterized.Parameters.method_dependencies.rst.txt @@ -0,0 +1,6 @@ +param.parameterized.Parameters.method\_dependencies +=================================================== + +.. currentmodule:: param.parameterized + +.. automethod:: Parameters.method_dependencies \ No newline at end of file diff --git a/_sources/reference/param/generated/param.parameterized.Parameters.objects.rst.txt b/_sources/reference/param/generated/param.parameterized.Parameters.objects.rst.txt new file mode 100644 index 0000000..32d3cd1 --- /dev/null +++ b/_sources/reference/param/generated/param.parameterized.Parameters.objects.rst.txt @@ -0,0 +1,6 @@ +param.parameterized.Parameters.objects +====================================== + +.. currentmodule:: param.parameterized + +.. automethod:: Parameters.objects \ No newline at end of file diff --git a/_sources/reference/param/generated/param.parameterized.Parameters.outputs.rst.txt b/_sources/reference/param/generated/param.parameterized.Parameters.outputs.rst.txt new file mode 100644 index 0000000..d8c421a --- /dev/null +++ b/_sources/reference/param/generated/param.parameterized.Parameters.outputs.rst.txt @@ -0,0 +1,6 @@ +param.parameterized.Parameters.outputs +====================================== + +.. currentmodule:: param.parameterized + +.. automethod:: Parameters.outputs \ No newline at end of file diff --git a/_sources/reference/param/generated/param.parameterized.Parameters.params.rst.txt b/_sources/reference/param/generated/param.parameterized.Parameters.params.rst.txt new file mode 100644 index 0000000..0962436 --- /dev/null +++ b/_sources/reference/param/generated/param.parameterized.Parameters.params.rst.txt @@ -0,0 +1,6 @@ +param.parameterized.Parameters.params +===================================== + +.. currentmodule:: param.parameterized + +.. automethod:: Parameters.params \ No newline at end of file diff --git a/_sources/reference/param/generated/param.parameterized.Parameters.params_depended_on.rst.txt b/_sources/reference/param/generated/param.parameterized.Parameters.params_depended_on.rst.txt new file mode 100644 index 0000000..3bad81b --- /dev/null +++ b/_sources/reference/param/generated/param.parameterized.Parameters.params_depended_on.rst.txt @@ -0,0 +1,6 @@ +param.parameterized.Parameters.params\_depended\_on +=================================================== + +.. currentmodule:: param.parameterized + +.. automethod:: Parameters.params_depended_on \ No newline at end of file diff --git a/_sources/reference/param/generated/param.parameterized.Parameters.pprint.rst.txt b/_sources/reference/param/generated/param.parameterized.Parameters.pprint.rst.txt new file mode 100644 index 0000000..2a3f97f --- /dev/null +++ b/_sources/reference/param/generated/param.parameterized.Parameters.pprint.rst.txt @@ -0,0 +1,6 @@ +param.parameterized.Parameters.pprint +===================================== + +.. currentmodule:: param.parameterized + +.. automethod:: Parameters.pprint \ No newline at end of file diff --git a/_sources/reference/param/generated/param.parameterized.Parameters.print_param_defaults.rst.txt b/_sources/reference/param/generated/param.parameterized.Parameters.print_param_defaults.rst.txt new file mode 100644 index 0000000..cdf3c59 --- /dev/null +++ b/_sources/reference/param/generated/param.parameterized.Parameters.print_param_defaults.rst.txt @@ -0,0 +1,6 @@ +param.parameterized.Parameters.print\_param\_defaults +===================================================== + +.. currentmodule:: param.parameterized + +.. automethod:: Parameters.print_param_defaults \ No newline at end of file diff --git a/_sources/reference/param/generated/param.parameterized.Parameters.print_param_values.rst.txt b/_sources/reference/param/generated/param.parameterized.Parameters.print_param_values.rst.txt new file mode 100644 index 0000000..50a8e1c --- /dev/null +++ b/_sources/reference/param/generated/param.parameterized.Parameters.print_param_values.rst.txt @@ -0,0 +1,6 @@ +param.parameterized.Parameters.print\_param\_values +=================================================== + +.. currentmodule:: param.parameterized + +.. automethod:: Parameters.print_param_values \ No newline at end of file diff --git a/_sources/reference/param/generated/param.parameterized.Parameters.schema.rst.txt b/_sources/reference/param/generated/param.parameterized.Parameters.schema.rst.txt new file mode 100644 index 0000000..ca3aee9 --- /dev/null +++ b/_sources/reference/param/generated/param.parameterized.Parameters.schema.rst.txt @@ -0,0 +1,6 @@ +param.parameterized.Parameters.schema +===================================== + +.. currentmodule:: param.parameterized + +.. automethod:: Parameters.schema \ No newline at end of file diff --git a/_sources/reference/param/generated/param.parameterized.Parameters.serialize_parameters.rst.txt b/_sources/reference/param/generated/param.parameterized.Parameters.serialize_parameters.rst.txt new file mode 100644 index 0000000..d02b7ef --- /dev/null +++ b/_sources/reference/param/generated/param.parameterized.Parameters.serialize_parameters.rst.txt @@ -0,0 +1,6 @@ +param.parameterized.Parameters.serialize\_parameters +==================================================== + +.. currentmodule:: param.parameterized + +.. automethod:: Parameters.serialize_parameters \ No newline at end of file diff --git a/_sources/reference/param/generated/param.parameterized.Parameters.serialize_value.rst.txt b/_sources/reference/param/generated/param.parameterized.Parameters.serialize_value.rst.txt new file mode 100644 index 0000000..3a8e8db --- /dev/null +++ b/_sources/reference/param/generated/param.parameterized.Parameters.serialize_value.rst.txt @@ -0,0 +1,6 @@ +param.parameterized.Parameters.serialize\_value +=============================================== + +.. currentmodule:: param.parameterized + +.. automethod:: Parameters.serialize_value \ No newline at end of file diff --git a/_sources/reference/param/generated/param.parameterized.Parameters.set_default.rst.txt b/_sources/reference/param/generated/param.parameterized.Parameters.set_default.rst.txt new file mode 100644 index 0000000..6e99022 --- /dev/null +++ b/_sources/reference/param/generated/param.parameterized.Parameters.set_default.rst.txt @@ -0,0 +1,6 @@ +param.parameterized.Parameters.set\_default +=========================================== + +.. currentmodule:: param.parameterized + +.. automethod:: Parameters.set_default \ No newline at end of file diff --git a/_sources/reference/param/generated/param.parameterized.Parameters.set_dynamic_time_fn.rst.txt b/_sources/reference/param/generated/param.parameterized.Parameters.set_dynamic_time_fn.rst.txt new file mode 100644 index 0000000..5d6b289 --- /dev/null +++ b/_sources/reference/param/generated/param.parameterized.Parameters.set_dynamic_time_fn.rst.txt @@ -0,0 +1,6 @@ +param.parameterized.Parameters.set\_dynamic\_time\_fn +===================================================== + +.. currentmodule:: param.parameterized + +.. automethod:: Parameters.set_dynamic_time_fn \ No newline at end of file diff --git a/_sources/reference/param/generated/param.parameterized.Parameters.set_param.rst.txt b/_sources/reference/param/generated/param.parameterized.Parameters.set_param.rst.txt new file mode 100644 index 0000000..474b470 --- /dev/null +++ b/_sources/reference/param/generated/param.parameterized.Parameters.set_param.rst.txt @@ -0,0 +1,6 @@ +param.parameterized.Parameters.set\_param +========================================= + +.. currentmodule:: param.parameterized + +.. automethod:: Parameters.set_param \ No newline at end of file diff --git a/_sources/reference/param/generated/param.parameterized.Parameters.trigger.rst.txt b/_sources/reference/param/generated/param.parameterized.Parameters.trigger.rst.txt new file mode 100644 index 0000000..e7ab02b --- /dev/null +++ b/_sources/reference/param/generated/param.parameterized.Parameters.trigger.rst.txt @@ -0,0 +1,6 @@ +param.parameterized.Parameters.trigger +====================================== + +.. currentmodule:: param.parameterized + +.. automethod:: Parameters.trigger \ No newline at end of file diff --git a/_sources/reference/param/generated/param.parameterized.Parameters.unwatch.rst.txt b/_sources/reference/param/generated/param.parameterized.Parameters.unwatch.rst.txt new file mode 100644 index 0000000..01456cd --- /dev/null +++ b/_sources/reference/param/generated/param.parameterized.Parameters.unwatch.rst.txt @@ -0,0 +1,6 @@ +param.parameterized.Parameters.unwatch +====================================== + +.. currentmodule:: param.parameterized + +.. automethod:: Parameters.unwatch \ No newline at end of file diff --git a/_sources/reference/param/generated/param.parameterized.Parameters.update.rst.txt b/_sources/reference/param/generated/param.parameterized.Parameters.update.rst.txt new file mode 100644 index 0000000..6724574 --- /dev/null +++ b/_sources/reference/param/generated/param.parameterized.Parameters.update.rst.txt @@ -0,0 +1,6 @@ +param.parameterized.Parameters.update +===================================== + +.. currentmodule:: param.parameterized + +.. automethod:: Parameters.update \ No newline at end of file diff --git a/_sources/reference/param/generated/param.parameterized.Parameters.values.rst.txt b/_sources/reference/param/generated/param.parameterized.Parameters.values.rst.txt new file mode 100644 index 0000000..7f7af0d --- /dev/null +++ b/_sources/reference/param/generated/param.parameterized.Parameters.values.rst.txt @@ -0,0 +1,6 @@ +param.parameterized.Parameters.values +===================================== + +.. currentmodule:: param.parameterized + +.. automethod:: Parameters.values \ No newline at end of file diff --git a/_sources/reference/param/generated/param.parameterized.Parameters.verbose.rst.txt b/_sources/reference/param/generated/param.parameterized.Parameters.verbose.rst.txt new file mode 100644 index 0000000..6322d89 --- /dev/null +++ b/_sources/reference/param/generated/param.parameterized.Parameters.verbose.rst.txt @@ -0,0 +1,6 @@ +param.parameterized.Parameters.verbose +====================================== + +.. currentmodule:: param.parameterized + +.. automethod:: Parameters.verbose \ No newline at end of file diff --git a/_sources/reference/param/generated/param.parameterized.Parameters.warning.rst.txt b/_sources/reference/param/generated/param.parameterized.Parameters.warning.rst.txt new file mode 100644 index 0000000..4a46350 --- /dev/null +++ b/_sources/reference/param/generated/param.parameterized.Parameters.warning.rst.txt @@ -0,0 +1,6 @@ +param.parameterized.Parameters.warning +====================================== + +.. currentmodule:: param.parameterized + +.. automethod:: Parameters.warning \ No newline at end of file diff --git a/_sources/reference/param/generated/param.parameterized.Parameters.watch.rst.txt b/_sources/reference/param/generated/param.parameterized.Parameters.watch.rst.txt new file mode 100644 index 0000000..52b1252 --- /dev/null +++ b/_sources/reference/param/generated/param.parameterized.Parameters.watch.rst.txt @@ -0,0 +1,6 @@ +param.parameterized.Parameters.watch +==================================== + +.. currentmodule:: param.parameterized + +.. automethod:: Parameters.watch \ No newline at end of file diff --git a/_sources/reference/param/generated/param.parameterized.Parameters.watch_values.rst.txt b/_sources/reference/param/generated/param.parameterized.Parameters.watch_values.rst.txt new file mode 100644 index 0000000..e4636a8 --- /dev/null +++ b/_sources/reference/param/generated/param.parameterized.Parameters.watch_values.rst.txt @@ -0,0 +1,6 @@ +param.parameterized.Parameters.watch\_values +============================================ + +.. currentmodule:: param.parameterized + +.. automethod:: Parameters.watch_values \ No newline at end of file diff --git a/_sources/reference/param/generated/param.parameterized.Parameters.watchers.rst.txt b/_sources/reference/param/generated/param.parameterized.Parameters.watchers.rst.txt new file mode 100644 index 0000000..e6e99a9 --- /dev/null +++ b/_sources/reference/param/generated/param.parameterized.Parameters.watchers.rst.txt @@ -0,0 +1,6 @@ +param.parameterized.Parameters.watchers +======================================= + +.. currentmodule:: param.parameterized + +.. autoproperty:: Parameters.watchers \ No newline at end of file diff --git a/_sources/reference/param/generated/param.parameterized.Watcher.rst.txt b/_sources/reference/param/generated/param.parameterized.Watcher.rst.txt new file mode 100644 index 0000000..9c52a07 --- /dev/null +++ b/_sources/reference/param/generated/param.parameterized.Watcher.rst.txt @@ -0,0 +1,38 @@ +param.parameterized.Watcher +=========================== + +.. currentmodule:: param.parameterized + +.. autoclass:: Watcher + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~Watcher.__init__ + ~Watcher.count + ~Watcher.index + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~Watcher.cls + ~Watcher.fn + ~Watcher.inst + ~Watcher.mode + ~Watcher.onlychanged + ~Watcher.parameter_names + ~Watcher.precedence + ~Watcher.queued + ~Watcher.what + + \ No newline at end of file diff --git a/_sources/reference/param/generated/param.parameterized.batch_call_watchers.rst.txt b/_sources/reference/param/generated/param.parameterized.batch_call_watchers.rst.txt new file mode 100644 index 0000000..5bfa984 --- /dev/null +++ b/_sources/reference/param/generated/param.parameterized.batch_call_watchers.rst.txt @@ -0,0 +1,6 @@ +param.parameterized.batch\_call\_watchers +========================================= + +.. currentmodule:: param.parameterized + +.. autofunction:: batch_call_watchers \ No newline at end of file diff --git a/_sources/reference/param/generated/param.parameterized.get_logger.rst.txt b/_sources/reference/param/generated/param.parameterized.get_logger.rst.txt new file mode 100644 index 0000000..8b5f105 --- /dev/null +++ b/_sources/reference/param/generated/param.parameterized.get_logger.rst.txt @@ -0,0 +1,6 @@ +param.parameterized.get\_logger +=============================== + +.. currentmodule:: param.parameterized + +.. autofunction:: get_logger \ No newline at end of file diff --git a/_sources/reference/param/generated/param.parameterized.logging_level.rst.txt b/_sources/reference/param/generated/param.parameterized.logging_level.rst.txt new file mode 100644 index 0000000..374168a --- /dev/null +++ b/_sources/reference/param/generated/param.parameterized.logging_level.rst.txt @@ -0,0 +1,6 @@ +param.parameterized.logging\_level +================================== + +.. currentmodule:: param.parameterized + +.. autofunction:: logging_level \ No newline at end of file diff --git a/_sources/reference/param/generated/param.script_repr.rst.txt b/_sources/reference/param/generated/param.script_repr.rst.txt new file mode 100644 index 0000000..b59284a --- /dev/null +++ b/_sources/reference/param/generated/param.script_repr.rst.txt @@ -0,0 +1,6 @@ +param.script\_repr +================== + +.. currentmodule:: param + +.. autofunction:: script_repr \ No newline at end of file diff --git a/_sources/reference/param/index.md.txt b/_sources/reference/param/index.md.txt new file mode 100644 index 0000000..c2fd749 --- /dev/null +++ b/_sources/reference/param/index.md.txt @@ -0,0 +1,57 @@ +# Param API reference + +## Parameterized objects + +```{include} parameterized_objects.md +:start-line: 2 +``` + +## Parameterized helpers + +```{include} parameterized_helpers.md +:start-line: 2 +``` + +## Parameters + +```{include} parameters.md +:start-line: 2 +``` + +## Parameter helpers + +```{include} parameter_helpers.md +:start-line: 2 +``` + +## `.param` namespace + +```{include} param_namespace.md +:start-line: 2 +``` + +## Logging + +```{include} logging.md +:start-line: 2 +``` + +## Serialization + +```{include} serialization.md +:start-line: 2 +``` + +```{toctree} +--- +maxdepth: 2 +hidden: true +--- +Parameterized objects +Parameterized helpers +Parameters +Parameter helpers +Param namespace +Logging +Serialization +``` diff --git a/_sources/reference/param/logging.md.txt b/_sources/reference/param/logging.md.txt new file mode 100644 index 0000000..83947a7 --- /dev/null +++ b/_sources/reference/param/logging.md.txt @@ -0,0 +1,9 @@ +# Logging + +```{eval-rst} +.. autosummary:: + :toctree: generated/ + + param.parameterized.get_logger + param.parameterized.logging_level +``` diff --git a/_sources/reference/param/param_namespace.md.txt b/_sources/reference/param/param_namespace.md.txt new file mode 100644 index 0000000..da7f17e --- /dev/null +++ b/_sources/reference/param/param_namespace.md.txt @@ -0,0 +1,48 @@ +# `.param` namespace + +These methods and properties are available under the `.param` namespace +of {py:class}`Parameterized` classes and instances. + +```{eval-rst} +.. currentmodule:: param.parameterized +``` + +```{eval-rst} +.. autosummary:: + :toctree: generated/ + + ~Parameters.add_parameter + ~Parameters.debug + ~Parameters.defaults + ~Parameters.deserialize_parameters + ~Parameters.deserialize_value + ~Parameters.force_new_dynamic_value + ~Parameters.get_param_values + ~Parameters.get_value_generator + ~Parameters.inspect_value + ~Parameters.log + ~Parameters.message + ~Parameters.method_dependencies + ~Parameters.objects + ~Parameters.outputs + ~Parameters.params + ~Parameters.params_depended_on + ~Parameters.pprint + ~Parameters.print_param_defaults + ~Parameters.print_param_values + ~Parameters.schema + ~Parameters.set_default + ~Parameters.set_dynamic_time_fn + ~Parameters.set_param + ~Parameters.serialize_parameters + ~Parameters.serialize_value + ~Parameters.trigger + ~Parameters.unwatch + ~Parameters.update + ~Parameters.values + ~Parameters.verbose + ~Parameters.warning + ~Parameters.watch + ~Parameters.watch_values + ~Parameters.watchers +``` diff --git a/_sources/reference/param/parameter_helpers.md.txt b/_sources/reference/param/parameter_helpers.md.txt new file mode 100644 index 0000000..65e1122 --- /dev/null +++ b/_sources/reference/param/parameter_helpers.md.txt @@ -0,0 +1,16 @@ +# Parameter helpers + +```{eval-rst} +.. currentmodule:: param +``` + +```{eval-rst} +.. autosummary:: + :toctree: generated/ + + get_soft_bounds + guess_bounds + guess_param_types + param_union + ParamOverrides +``` diff --git a/_sources/reference/param/parameterized_helpers.md.txt b/_sources/reference/param/parameterized_helpers.md.txt new file mode 100644 index 0000000..6fb6b42 --- /dev/null +++ b/_sources/reference/param/parameterized_helpers.md.txt @@ -0,0 +1,21 @@ +# Parameterized helpers + +```{eval-rst} +.. currentmodule:: param +``` + +```{eval-rst} +.. autosummary:: + :toctree: generated/ + + param.parameterized.Event + param.parameterized.Watcher + batch_watch + param.parameterized.batch_call_watchers + concrete_descendents + depends + discard_events + edit_constant + output + script_repr +``` diff --git a/_sources/reference/param/parameterized_objects.md.txt b/_sources/reference/param/parameterized_objects.md.txt new file mode 100644 index 0000000..7ff607b --- /dev/null +++ b/_sources/reference/param/parameterized_objects.md.txt @@ -0,0 +1,14 @@ +# Parameterized objects + +```{eval-rst} +.. currentmodule:: param +``` + +```{eval-rst} +.. autosummary:: + :toctree: generated/ + :nosignatures: + + Parameterized + ParameterizedFunction +``` diff --git a/_sources/reference/param/parameters.md.txt b/_sources/reference/param/parameters.md.txt new file mode 100644 index 0000000..ab9f05e --- /dev/null +++ b/_sources/reference/param/parameters.md.txt @@ -0,0 +1,46 @@ +# Parameters + +```{eval-rst} +.. currentmodule:: param +``` + +```{eval-rst} +.. autosummary:: + :toctree: generated/ + :nosignatures: + + Parameter + String + Bytes + Color + Boolean + Event + Dynamic + Number + Integer + Magnitude + Tuple + NumericTuple + XYCoordinates + Range + DateRange + CalendarDateRange + List + HookList + Path + Filename + Foldername + CalendarDateRange + Selector + FileSelector + ListSelector + MultiFileSelector + ClassSelector + Dict + Array + Series + DataFrame + Callable + Action + Composite +``` diff --git a/_sources/reference/param/serialization.md.txt b/_sources/reference/param/serialization.md.txt new file mode 100644 index 0000000..1dad4bd --- /dev/null +++ b/_sources/reference/param/serialization.md.txt @@ -0,0 +1,7 @@ +# Serialization + +```{eval-rst} +.. automodule :: param.serializer + :members: + :undoc-members: +``` diff --git a/_sources/releases.md.txt b/_sources/releases.md.txt new file mode 100644 index 0000000..20a6d58 --- /dev/null +++ b/_sources/releases.md.txt @@ -0,0 +1,438 @@ +# Releases + +## Version 1.13.0 + +Date: 2023-03-14 + +The `1.13.0` is the last release of Param before the 2.0 release. However, Param 1.13 is meant to receive long-term support; security patches and fixes to critical bugs are planned to be backported to the 1.13.x series. + +This release includes a new `Bytes` *Parameter* and a few important bug fixes. This release is also marked by the adoption of a formal project governance, ensuring Param's future as a healthy open-source project. Many thanks to @ovidner and @droumis for their first contributions! And to @maximlt, @Hoxbro, @jlstevens, @philippjfr and @jbednar for their continuing support to fixing and improving Param. + +Bug fixes: + +* Fix copying when having watchers on e.g. bounds on inherited Parameter types ([#675](https://github.com/holoviz/param/pull/675)) +* Allow JSON serialization to work with `json.dumps` ([#655](https://github.com/holoviz/param/pull/655)) +* `ListSelector` restricted to `list` type objects ([#531](https://github.com/holoviz/param/pull/531)) +* Fix `depends` async wrapper ([#684](https://github.com/holoviz/param/pull/684)) +* Allow named colors to be any case ([#711](https://github.com/holoviz/param/pull/711)) + +New features: + +* Add Bytes parameter ([#542](https://github.com/holoviz/param/pull/542)) + +Documentation: + +* Fix param module link ([#682](https://github.com/holoviz/param/pull/682)) + +Project governance: + +* Create initial project governance docs ([#674](https://github.com/holoviz/param/pull/674)) + +Maintenance: + +* Rename `master` branch to `main` ([#672](https://github.com/holoviz/param/pull/672)) +* Add more tests ([#710](https://github.com/holoviz/param/pull/710)) +* Various CI related fixes ([#680](https://github.com/holoviz/param/pull/680), [#683](https://github.com/holoviz/param/pull/683) and [#709](https://github.com/holoviz/param/pull/709)) + +## Version 1.12.3 + +Date: 2022-12-06 + +The `1.12.3` release adds support for Python 3.11. Many thanks to @musicinmybrain (first contribution!) and @maximlt for contributing to this release. + +Enhancements: + +* Preserve existing Random seed behavior in Python 3.11 ([#638](https://github.com/holoviz/param/pull/638)) +* Add support for Python 3.11 ([#658](https://github.com/holoviz/param/pull/658)) + +## Version 1.12.2 + +Date: 2022-06-14 + +The `1.12.2` release fixes a number of bugs and adds support again for Python 2.7, which was unfortunately no longer supported in the last release. Note however that Param 2.0 will still drop support of Python 2.7 as already announced. Many thanks to @Hoxbro and the maintainers @jbednar, @jlstevens, @maximlt and @philippjfr for contributing to this release. + +Bug fixes: + +* Match against complete spec name when determining dynamic watchers ([#615](https://github.com/holoviz/param/pull/615)) +* Ensure async functionality does not cause python2 syntax errors ([#624](https://github.com/holoviz/param/pull/624)) +* Allow (de)serializing `CalendarRange` and `DateRange` `Parameters` ([#625](https://github.com/holoviz/param/pull/625)) +* Improve `DateRange` validation ([#627](https://github.com/holoviz/param/pull/627)) +* Fix regression in `@param.depends` execution ordering ([#628](https://github.com/holoviz/param/pull/628)) +* Ensure `named_objs` does not fail on unhashable objects ([#632](https://github.com/holoviz/param/pull/632)) +* Support comparing date-like objects ([#629](https://github.com/holoviz/param/pull/629)) +* Fixed `BinaryPower` example in the docs to use the correct name `EvenInteger`([#634](https://github.com/holoviz/param/pull/634)) + +## Version 1.12.1 + +The 1.12.1 release fixes a number of bugs related to async callback handling when using `param.depends` and `.param.watch` and a number of documentation and error messages. Many thanks to @HoxBro and the maintainers @jbednar, @jlstevens, @maximlt and @philippjfr for contributing to this release. + +Error handling and documentation: + +- Fixed description of shared_parameters ([#568](https://github.com/holoviz/param/pull/568)) +- Improve the error messages of Date and DateRange ([#579](https://github.com/holoviz/param/pull/579)) +- Clarified step error messages and other docs and links ([#604](https://github.com/holoviz/param/pull/604)) + +Bug fixes: + +- Make iscoroutinefunction more robust ([#572](https://github.com/holoviz/param/pull/572)) +- Fix for handling misspelled parameter ([#575](https://github.com/holoviz/param/pull/575)) +- Handle None serialization for Date, CalendarDate, Tuple, Array, and DataFrame ([#582](https://github.com/holoviz/param/pull/582)) +- Support async coroutines in param.depends ([#591](https://github.com/holoviz/param/pull/591)) +- Handle async functions in depends with watch=True ([#611](https://github.com/holoviz/param/pull/611)) +- Avoid equality check on Watcher ([#612](https://github.com/holoviz/param/pull/612)) + +Documentation: + +- Fix binder ([#564](https://github.com/holoviz/param/pull/564)) +- Fixed description of shared_parameters ([#568](https://github.com/holoviz/param/pull/568)) + +## Version 1.12.0 + +Version 1.12.0 introduces a complete user manual and website (for the first time since 2003!) along with extensive API improvements gearing up for the 2.0 release (which will be Python3 only). + +The pre-2.0 API is still being preserved and no new warnings are added in this release, so the older API can continue to be used with this release, but the next 1.x release is expected to enable warnings for deprecated API. If you have older code using the deprecated Param features below, please update your API calls as described below to be compatible with the 2.0 release when it comes out (or pin to param<2 if you don't need any new Param features). For new users, just use the API documented on the website, and you should be ready to go for either 1.12+ or 2.0+. + +Thanks to James A. Bednar for the user guide and 2.0 API support, to Philipp Rudiger for improvements and new capabilities for handling dependencies on subobjects, and to Maxime Liquet and Philipp Rudiger for extensive improvements to the website/docs/package-building/testing. + +New features: +- Added future-facing API for certain Parameterized().param methods (see Compatibility below; [#556](https://github.com/holoviz/param/pull/556), [#558](https://github.com/holoviz/param/pull/558), [#559](https://github.com/holoviz/param/pull/559)) +- New option `on_init=True` for `@depends` decorator, to run the method in the constructor to ensure initial state is consistent when appropriate ([#540](https://github.com/holoviz/param/pull/540)) +- Now resolves subobject dependencies dynamically, allowing dependencies on internal parameters of subobjects to resolve appropriately as those objects are replaced. ([#552](https://github.com/holoviz/param/pull/552)) +- Added prettyprinting for numbergen expressions ([#525](https://github.com/holoviz/param/pull/525)) +- Improved JSON schema generation ([#458](https://github.com/holoviz/param/pull/458)) +- Added more-usable script_repr command, availabie in param namespace, with default values, and showing imports ([#522](https://github.com/holoviz/param/pull/522)) +- Added Parameterized.param.pprint(); underlying implementation of script_repr but with defaults suitable for interactive usage rather than generating a .py script. ([#522](https://github.com/holoviz/param/pull/522)) +- Watchers can now declare precedence so that events are triggered in the desired order ([#552](https://github.com/holoviz/param/pull/552), [#557](https://github.com/holoviz/param/pull/557)) + +Bug fixes: +- Fix bug setting attributes in some cases before class is initialized ([#544](https://github.com/holoviz/param/pull/544)) +- Ensure None is supported on ListSelector ([#511](https://github.com/holoviz/param/pull/511)) +- Switched from deprecated `inspect.getargspec` to the py3 version `inspect.getfullargspec`, which is similar but splits `keyword` args into `varkw` (**) and kw-only args. Falls back to getargspec on Python2. ([#521](https://github.com/holoviz/param/pull/521)) + +Doc improvements (including complete user guide for the first time!): +- Misc comments/docstrings/docs cleanup ([#507](https://github.com/holoviz/param/pull/507), [#518](https://github.com/holoviz/param/pull/518), [#528](https://github.com/holoviz/param/pull/528), [#553](https://github.com/holoviz/param/pull/553)) +- Added comparison with pydantic ([#523](https://github.com/holoviz/param/pull/523)) +- Added new user guide sections: + * Dependencies_and_Watchers user guide ([#536](https://github.com/holoviz/param/pull/536)) + * Dynamic Parameters ([#525](https://github.com/holoviz/param/pull/525)) + * Outputs ([#523](https://github.com/holoviz/param/pull/523)) + * Serialization and Persistence ([#523](https://github.com/holoviz/param/pull/523)) + +Infrastructure: +- Added testing on Python 3.10 and on Mac OS X and removed slow PyPy/pandas/numpy tests ([#548](https://github.com/holoviz/param/pull/548), [#549](https://github.com/holoviz/param/pull/549), [#526](https://github.com/holoviz/param/pull/526)) +- Docs/tests/build infrastructure improvements ([#509](https://github.com/holoviz/param/pull/509), [#521](https://github.com/holoviz/param/pull/521), [#529](https://github.com/holoviz/param/pull/529), [#530](https://github.com/holoviz/param/pull/530), [#537](https://github.com/holoviz/param/pull/537), [#538](https://github.com/holoviz/param/pull/538), [#539](https://github.com/holoviz/param/pull/539), [#547](https://github.com/holoviz/param/pull/547), [#548](https://github.com/holoviz/param/pull/548), [#555](https://github.com/holoviz/param/pull/555)) + +Compatibility (see [#543](https://github.com/holoviz/param/pull/543) for the complete list): +- Calendardate now accepts date values only ([#517](https://github.com/holoviz/param/pull/517)) +- No longer allows modifying name of a Parameter once it is in a Parameterized class, to avoid confusion ([#541](https://github.com/holoviz/param/pull/541)) +- Renamed (with old name still accepted for compatibility until 2.0): + * `.param._add_parameter()`: Now public `.param.add_parameter()`; too useful to keep private! ([#559](https://github.com/holoviz/param/pull/559)) + * `.param.params_depended_on`: Now `.param.method_dependencies` to indicate that it accepts a method name and returns its dependencies ([#559](https://github.com/holoviz/param/pull/559)) + * `.pprint`: Now private `._pprint`; use public `.param.pprint` instead ([#559](https://github.com/holoviz/param/pull/559)) + * `batch_watch`: Now `batch_call_watchers`, to declare that it does not set up watching, it just invokes it. Removed unused operation argument ([#536](https://github.com/holoviz/param/pull/536)) + +- Deprecated (but not yet warning unless noted): + * `.param.debug()`: Use `.param.log(param.DEBUG, ...)` instead ([#556](https://github.com/holoviz/param/pull/556)) + * `.param.verbose()`: Use `.param.log(param.VERBOSE, ...)` instead ([#556](https://github.com/holoviz/param/pull/556)) + * `.param.message()`: Use `.param.log(param.MESSAGE, ...)` instead ([#556](https://github.com/holoviz/param/pull/556)) + * `.param.defaults()`: Use `{k:v.default for k,v in p.param.objects().items()}` instead ([#559](https://github.com/holoviz/param/pull/559)) + * `.param.deprecate()`: To be repurposed or deleted after 2.0 ([#559](https://github.com/holoviz/param/pull/559)) + * `.param.params()`: Use `.param.values()` or `.param['param']` instead ([#559](https://github.com/holoviz/param/pull/559)) + * `.param.print_param_defaults()`: Use `for k,v in p.param.objects().items(): print(f"{p.__class__.name}.{k}={repr(v.default)}")` instead ([#559](https://github.com/holoviz/param/pull/559)) + * `.param.print_param_values()`: Use `for k,v in p.param.values().items(): print(f"{p.name}.{k}={v}")` instead ([#559](https://github.com/holoviz/param/pull/559)) + * `.param.set_default()`: Use `p.param.default=` instead ([#559](https://github.com/holoviz/param/pull/559)) + * `.param.set_param()`: Had tricky API; use `.param.update` instead ([#558](https://github.com/holoviz/param/pull/558)) + * `.param.get_param_values()`: Use `.param.values().items()` instead (or `.param.values()` for the common case of `dict(....param.get_param_values())`) ([#559](https://github.com/holoviz/param/pull/559)) + * `.state_pop()`: Will be renamed to `._state_pop` to make private + * `.state_push()`: Will be renamed to `._state_push` to make private + * `.initialized`: Will be renamed to `._initialized` to make private + * Most methods on Parameterized itself have already been deprecated and warning for some time now; see [#543](https://github.com/holoviz/param/pull/543) for the list. Use the corresponding method on the `.param` accessor instead. + +- Added: + * `.param.watchers`: Read-only version of private `_watchers` ([#559](https://github.com/holoviz/param/pull/559)) + * `.param.log()`: Subsumes .debug/verbose/message; all are logging calls. ([#556](https://github.com/holoviz/param/pull/556)) + * `.param.update()`: Dictionary-style updates to parameter values, as a drop-in replacement for `set_param` except for its optional legacy positional-arg syntax ([#558](https://github.com/holoviz/param/pull/558)) + * `.values()`: Dictionary of name:value pairs for parameter values, replacing `get_param_values` but now a dict since python3 preserves order ([#558](https://github.com/holoviz/param/pull/558)) + * `.param.log()`: General-purpose interface to the logging module functionailty; replaces .debug, .verbose, .message ([#556](https://github.com/holoviz/param/pull/556)) + +## Version 1.11.1 + +(including changes in 1.11.0; 1.11.1 adds only a minor change to fix `param.List(None)`.) + +Version 1.11 contains entirely new [documentation](https://param.holoviz.org), plus various enhancements and bugfixess. Thanks to James A. Bednar for the documentation, Philipp Rudiger for the website setup and for many of the other fixes and improvements below, and others as noted below. + +Documentation: +- Brand-new website, with getting started, user manual, reference manual, and more! Some user guide sections are still under construction. ([#428](https://github.com/holoviz/param/pull/428),[#464](https://github.com/holoviz/param/pull/464),[#479](https://github.com/holoviz/param/pull/479),[#483](https://github.com/holoviz/param/pull/483),[#501](https://github.com/holoviz/param/pull/501),[#502](https://github.com/holoviz/param/pull/502),[#503](https://github.com/holoviz/param/pull/503),[#504](https://github.com/holoviz/param/pull/504)) +- New intro video with examples/Promo.ipynb notebook, thanks to Marc Skov Madsen and Egbert Ammicht ([#488](https://github.com/holoviz/param/pull/488)) +- Sort docstring by definition order and precedence, thanks to Andrew Huang ([#445](https://github.com/holoviz/param/pull/445)) + +Enhancements: +- Allow printing representations for recursively nested Parameterized objects ([#499](https://github.com/holoviz/param/pull/499)) +- Allow named colors for param.Color ([#472](https://github.com/holoviz/param/pull/472)) +- Allow FileSelector and MultiFileSelector to accept initial values ([#497](https://github.com/holoviz/param/pull/497)) +- Add Step slot to Range, thanks to Simon Hansen ([#467](https://github.com/holoviz/param/pull/467)) +- Update FileSelector and MultiFileSelector parameters when setting path ([#476](https://github.com/holoviz/param/pull/476)) +- Improved error messages ([#475](https://github.com/holoviz/param/pull/475)) + +Bug Fixes: +- Fix Path to allow folders, as documented but previously not supported ([#495](https://github.com/holoviz/param/pull/495)) +- Fix previously unimplemented Parameter._on_set ([#484](https://github.com/holoviz/param/pull/484)) +- Fix Python2 IPython output parameter precedence ([#477](https://github.com/holoviz/param/pull/477)) +- Fix allow_None for param.Series and param.DataFrame ([#473](https://github.com/holoviz/param/pull/473)) +- Fix behavior when both `instantiate` and `constant` are `True` ([#474](https://github.com/holoviz/param/pull/474)) +- Fix for versioning when param is inside a separate git-controlled repo (port of fix from autover/pull/67) ([#469](https://github.com/holoviz/param/pull/469)) + +Compatibility: +- Swapped ObjectSelector and Selector in the inheritance hierarchy, to allow ObjectSelector to be deprecated. ([#497](https://github.com/holoviz/param/pull/497)) +- Now `get_soft_bounds`silently crops softbounds to any hard bounds supplied ; previously soft bounds would be returned even if they were outside the hard bounds ([#498](https://github.com/holoviz/param/pull/498)) +- Rename `class_` to `item_type` in List parameter, to avoid clashing semantics with ClassSelector and others with a `class_` slot. `class_` is still accepted as a keyword but is stored in `item_type`. ([#456](https://github.com/holoviz/param/pull/456)) + +## Version 1.10.1 + +Minor release for Panel-related bugfixes and minor features, from @philippjfr. + +- Fix serialization of Tuple, for use in Panel ([#446](https://github.com/holoviz/param/pull/446)) +- Declare asynchronous executor for Panel to use ([#449](https://github.com/holoviz/param/pull/449)) +- Switch to GitHub Actions ([#450](https://github.com/holoviz/param/pull/450)) + +## Version 1.10.0 + +## Version 1.9.3 + +- Fixed ClassSelector.get_range when a tuple of types is supplied ([#360](https://github.com/holoviz/param/pull/360)) + +## Version 1.9.2 + +- Compatibility with Python 3.8 +- Add eager option to watch calls ([#351](https://github.com/holoviz/param/pull/351)) +- Add Calendar and CalendarDateRange for real date types ([#348](https://github.com/holoviz/param/pull/348)) + +## Version 1.9.1 + +Enhancements: + +- Allow param.depends to annotate functions ([#334](https://github.com/holoviz/param/pull/334)) +- Add context managers to manage events and edit constant parameters + +Bug fixes: + +- Ensure that Select constructor does not rely on truthiness ([#337](https://github.com/holoviz/param/pull/337)) +- Ensure that param.depends allows mixed Parameter types ([#338](https://github.com/holoviz/param/pull/338)) +- Date and DateRange now allow dt.date type ([#341](https://github.com/holoviz/param/pull/341)) +- Ensure events aren't dropped in batched mode ([#343](https://github.com/holoviz/param/pull/343)) + +## Version 1.9.0 + +Full release with new functionality and some fixes. New features: + +- Added support for instance parameters, allowing parameter metadata to be modified per instance and allowing parameter objects to be passed to Panel objects ([#306](https://github.com/holoviz/param/pull/306)) +- Added label slot to Parameter, to allow overriding attribute name for display ([#319](https://github.com/holoviz/param/pull/319)) +- Added step slot to Parameter, e.g. to control Panel widget step size ([#326](https://github.com/holoviz/param/pull/326)) +- Added keywords_to_params utility for deducing Parameter types and ranges automatically ([#317](https://github.com/holoviz/param/pull/317)) +- Added support for multiple outputs from a Parameterized ([#312](https://github.com/holoviz/param/pull/312)) +- Added Selector as a more user-friendly version of ObjectSelector, accepting a list of options as a positional argument ([#316](https://github.com/holoviz/param/pull/316)) + +Changes affecting backwards compatibility: + +- Changed from root logger to a param-specific logger; no change to API but will change format of error and warning messages ([#330](https://github.com/holoviz/param/pull/330)) +- Old abstract class Selector renamed to SelectorBase; should be no change unless user code added custom classes inherited from Selector without providing a constructor ([#316](https://github.com/holoviz/param/pull/316)) + +Bugfixes and other improvements: + +- Various bugfixes ([#320](https://github.com/holoviz/param/pull/320), [#323](https://github.com/holoviz/param/pull/323), [#327](https://github.com/holoviz/param/pull/327), [#329](https://github.com/holoviz/param/pull/329)) +- Other improvements ([#315](https://github.com/holoviz/param/pull/315), [#325](https://github.com/holoviz/param/pull/325)) + +For more details, you can see a [full list of changes since the previous release](https://github.com/holoviz/param/compare/v1.8.2...v1.9.0). + +## Version 1.8.2 + +Minor release: + +- Added output decorator and outputs lookup method ([#299](https://github.com/holoviz/param/pull/299), [#312](https://github.com/holoviz/param/pull/312)) + +For more details, you can see a [full list of changes since the previous release](https://github.com/holoviz/param/compare/v1.8.2...v1.8.1). + +## Version 1.8.1 + +Minor release: + +- Added positional default arguments for nearly all Parameter subclasses (apart from ClassSelector) +- Minor bugfixes for watching callbacks + +For more details, you can see a [full list of changes since the previous release](https://github.com/holoviz/param/compare/v1.8.1...v1.8.0). + +## Version 1.8.0 + +Major new feature set: comprehensive support for events, watching, callbacks, and dependencies + +- Parameterized methods can now declare `@depends(p,q)` to indicate that they depend on parameters `p` and `q` (defaulting to all parameters) +- Parameterized methods can depend on subobjects with `@depends(p.param,q.param.r)`, where `p.param` indicates dependencies on all parameters of `p` and `q.param.r` indicates a dependency on parameter `r` of `q`. +- Functions and methods can `watch` parameter values, re-running when those values change or when an explicit trigger is issued, and can unwatch them later if needed. +- Multiple events can be batched to trigger callbacks only once for a coordinated set of changes + +Other new features: + +- Added support in ObjectSelector for selecting lists and dicts ([#268](https://github.com/holoviz/param/pull/268)) +- Added pandas DataFrame and Series parameter types ([#285](https://github.com/holoviz/param/pull/285)) +- Added support for regular expression validation to String Parameter ([#241](https://github.com/holoviz/param/pull/241), [#245](https://github.com/holoviz/param/pull/245)) + +For more details, you can see a [full list of changes since the previous release](https://github.com/holoviz/param/compare/v1.8.0...v1.7.0). + +## Version 1.7.0 + +Since the previous release (1.6.1), there should be no changes that affect existing code, only additions: + +* A new param namespace object, which in future will allow subclasses of Parameterized to have much cleaner namespaces ([#230](https://github.com/holoviz/param/pull/230)). +* Started testing on python 3.7-dev ([#223](https://github.com/holoviz/param/pull/223)). +* param.version now provides functions to simplify dependants' setup.py/setup.cfg files (see https://github.com/holoviz-dev/autover/pull/49). + +Although param should still work on python 3.3, we are no longer testing against it (unsupported by our test environment; [#234](https://github.com/holoviz/param/pull/234)). + +For more details, you can see a [full list of changes since the previous release](https://github.com/holoviz/param/compare/v1.6.1...v1.7.0). + +## Version 1.6.1 + +Restores support for the previous versioning system (pre 1.6; see [#225](https://github.com/holoviz/param/pull/225)), and fixes a number of issues with the new versioning system: + +* Allow package name to differ from repository name (https://github.com/holoviz-dev/autover/pull/39) +* Allow develop install to work when repository is dirty (https://github.com/holoviz-dev/autover/pull/41) +* Fixed failure to report dirty when commit count is 0 (https://github.com/holoviz-dev/autover/pull/44) + +## Version 1.6.0 + +Notable changes, fixes, and additions since the previous release (1.5.1) are listed below. You can also see a [full list of changes since the previous release](https://github.com/holoviz/param/compare/v1.5.1...v1.6.0). + +Changes: +* `param.__version__` is now a string +* `param.version.Version` now supports a tag-based versioning workflow; if using the `Version` class, you will need to update your workflow (see [autover](https://github.com/holoviz-dev/autover) for more details). +* Dropped support for python 2.6 ([#175](https://github.com/holoviz/param/pull/175)). +* No longer attempt to cythonize param during installation via pip ([#166](https://github.com/holoviz/param/pull/166), [#194](https://github.com/holoviz/param/pull/194)). + +Fixes: +* Allow `get_param_values()` to work on class ([#162](https://github.com/holoviz/param/pull/162)). +* Fixed incorrect default value for `param.Integer` ([#151](https://github.com/holoviz/param/pull/151)). +* Allow a `String` to be `None` if its default is `None` ([#104](https://github.com/holoviz/param/pull/104)). +* Fixed `ListSelector.compute_default()` ([#212](https://github.com/holoviz/param/pull/212)). +* Fixed checks for `None` in various `Parameter` subclasses ([#208](https://github.com/holoviz/param/pull/208)); fixes problems for subclasses of `Parameterized` that define a custom `__nonzero__` or `__len__`. + +Additions: +* Added `DateRange` parameter. + +Miscellaneous: +* No longer tested on python 3.2 (unsupported by our test environment; [#218](https://github.com/holoviz/param/pull/218)). + +## Version 1.5.1 + +* Fixed error messages for ClassSelector with tuple of classes +* Added get and contains methods for ParamOverrides + +A full list of changes since the previous release is available [here](https://github.com/holoviz/param/compare/v1.5.0...v1.5.1). + +## Version 1.5.0 + +- Added Range, Color, and Date parameters +- Improved ObjectSelector error messages +- Minor bugfixes + +A full list of changes since the previous release is available [here](https://github.com/holoviz/param/compare/v1.4.2...v1.5.0). + +## Version 1.4.2 + +- Improved version reporting from version module +- Minor bugfixes + +A full list of changes since the previous release is available [here](https://github.com/holoviz/param/compare/v1.4.1...v1.4.2). + +## Version 1.4.1 + +* Selector parameters now respect order of options supplied +* Allowed softbounds to be accessed like an attribute + +A full list of changes since the previous release is available +[on GitHub](https://github.com/holoviz/param/compare/v1.4.0...v1.4.1). + +## Version 1.4.0 (2016/07) + +* Added support for new [ParamNB](https://github.com/ioam/paramnb) project +* Added new parameter types Action, FileSelector, and ListSelector + +A full list of changes since the previous release is available +[on GitHub](https://github.com/holoviz/param/compare/v1.3.2...v1.4.0). + +## Version 1.3.2 (2015/04) + +* Added Unicode support for param.String. +* Minor bugfixes. + +A full list of changes since the previous release is available +[on GitHub](https://github.com/holoviz/param/compare/v1.3.1...v1.3.2). + +## Version 1.3.1 (2015/03) + +* Minor bugfix release to restore pre-1.3.0 script_repr behavior + (accidentally changed in 1.3.0) and to fix issues with logging. +* Param's logging interface now matches that of Python's logging + module, making it simpler to use logging (see Python's logging + module for details). Note therefore that Param's logging methods (a) + no longer call functions that are passed as arguments (instead, + Python's logging module does lazy string merges), and (b) no longer + automatically combine strings passed as arguments (instead, Python's + logging module supports string formatting). +* Improved set_param() method, now allowing multiple parameters to be + set easily via keyword arguments (as on initialization). + +A full list of changes since the previous release is available +[on GitHub](https://github.com/holoviz/param/compare/v1.3.0...v1.3.1). + +## Version 1.3.0 (2015/03) + +* Added 'allow_None' support to all Parameters. Any subclass of + Parameter that checks types and/or values should be modified to add + appropriate handling of allow_None. +* Improved pretty printing (script_repr) of Parameterized instances, + and made available via the pprint method. The script_repr name will + be removed in a future release. +* Added (reproducible) time-dependent random streams + (numbergen.TimeAwareRandomState). +* Added label and unit parameters to param.Time class. +* Improved optional IPython extension. + +A full list of changes since the previous release is available +[on GitHub](https://github.com/holoviz/param/compare/v1.2.1...v1.3.0). + +## Version 1.2.1 (2014/06) + +* Minor bugfix release to fix issues with version when param is + installed in a foreign git repository +* Made version module optional +* Improved ClassSelector and ParamOverrides + +A full list of changes since the previous release is available +[on GitHub](https://github.com/holoviz/param/compare/v1.2.0...v1.2.1). + +## Version 1.2.0 (2014/06) + +* Added support for Python 3 (thanks to Marco Elver). +* Dropped support for Python 2.5. +* Added version module. +* Added optional numbergen package. + +A full list of changes since the previous release is available +[on GitHub](https://github.com/holoviz/param/compare/v1.1.0...v1.2.0). + +## Version 1.1.0 (2014/05) + +* Switched to Python's own logging module. +* Improved support for time when using Dynamic parameters. +* Optional extension for IPython users. + +A full list of changes since the previous release is available +[on GitHub](https://github.com/holoviz/param/compare/v1.0.0...v1.1.0). + +## Version 1.0.0 (2012/07) + +* First standalone release. + +## Pre-1.0 (2003) + +* Param was originally developed as part of [Topographica](http://ioam.github.io/topographica/), and has been in heavy usage as part of that project since 2003. diff --git a/_sources/roadmap.md.txt b/_sources/roadmap.md.txt new file mode 100644 index 0000000..b5d06f0 --- /dev/null +++ b/_sources/roadmap.md.txt @@ -0,0 +1,25 @@ +# Roadmap + +Param is a mature library (originally from 2003) that changes very slowly and very rarely; it is fully ready for use in production applications. Major changes are undertaken only after significant discussions and with attention to how existing Param-based applications will be affected. Thus Param users should not expect only slow progress on these roadmap items, but they are listed here in the hopes that they will be useful. + +Currently scheduled plans: + +- Remove deprecated API and tag release 2.0. Deprecated API is noted in the source code and except in very rare cases has never been documented on the website, so removing these methods should only affect users of Param from 2020 or earlier. + +- More powerful serialization (to JSON, YAML, and URLs) to make it simpler to persist the state of a Parameterized object. Some support already merged as https://github.com/holoviz/param/pull/414 , but still to be further developed as support for using Parameterized objects to build REST APIS (see https://github.com/holoviz/lumen for example usage). + +Other items that are not yet scheduled but would be great to have: + +- Integrate more fully with Python 3 language features like [type annotations](https://www.python.org/dev/peps/pep-0526) and [data classes](https://docs.python.org/3/library/dataclasses.html), e.g. to respect and validate against declared types without requiring an explicit `param.Parameter` declaration and potentially without inheriting from `param.Parameterized`, and to better support IDE type-checking features. + +- Integrate and interoperate more fully with other frameworks like Django models, Traitlets, attrs, Django models, Pydantic, or swagger/OpenAPI, each of which capture or can use similar information about parameter names, values, and constraints and so in many cases can easily be converted from one to the other. + +- Improve support for Param in editors, automatic formatting tools, linters, document generators, and other tools that process Python code and could be made to have special-purpose optimizations specifically for Parameterized objects. + +- Follow PEP8 more strictly: PEP8 definitely wasn't written with Parameters in mind, and it typically results in badly formatted files when applied to Parameterized code. But PEP8 could be applied to Param's own code, e.g. using Black. + +- Triaging open issues: The Param developer team consists of volunteers typically using Param on their projects but not explicity tasked with or funded to work on Param itself. It would thus be great if the more experienced Param users could help address some of the issues that have been raised but not yet solved. + +- Improve test coverage + +Other [issues](https://github.com/holoviz/param/issues) are collected on Github and will be addressed on various time scales as indicated by the issue's milestone (typically next minor release, next major release, or "wishlist" (not scheduled or assigned to any person but agreed to be desirable). Any contributor is encouraged to attempt to implement a "wishlist" item, though if it is particularly complex or time consuming it is useful to discuss it first with one of the core maintainers (e.g. by stating your intentions on the issue). diff --git a/_sources/user_guide/Dependencies_and_Watchers.ipynb.txt b/_sources/user_guide/Dependencies_and_Watchers.ipynb.txt new file mode 100644 index 0000000..8b5be3d --- /dev/null +++ b/_sources/user_guide/Dependencies_and_Watchers.ipynb.txt @@ -0,0 +1,901 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "33cd4c67", + "metadata": {}, + "source": [ + "# Dependencies and Watchers\n", + "\n", + "As outlined in the [Dynamic Parameters](Dynamic_Parameters.ipynb) guide, Param can be used in multiple ways, including as a static set of typed attributes, dynamic attributes that are computed when they are read (`param.Dynamic` parameters, a \"pull\" or \"get\" model), and using explicitly expressed chains of actions driven by events at the Parameter level (a \"push\" or \"set\" model described in this notebook). \n", + "\n", + "Unlike Dynamic Parameters, which calculate values when parameters are _accessed_, the dependency and watcher interface allows events to be triggered when parameters are _set_. With this interface, parameters and methods can declare that they should be updated or invoked when a given parameter is modified, spawning a cascading series of events that update settings to be consistent, adapt values as appropriate for a change, or invoke computations such as updating a displayed object when a value is modified. This approach is well suited to a GUI interface, where a user interacts with a single widget at a time but other widgets or displays need to be updated in response. The\n", + "[Dynamic Parameters](Dynamic_Parameters.ipynb) approach, in contrast, is well suited when Parameters update either on read or in response to a global clock or counter, such as in a simulation or machine-learning iteration.\n", + "\n", + "This user guide is structured as three main sections:\n", + "\n", + "- [Dependencies](#dependencies): High-level dependency declaration via the `@param.depends()` decorator\n", + "- [Watchers](#watchers): Low-level watching mechanism via `.param.watch()`.\n", + "- [Using dependencies and watchers](#using-dependencies-and-watchers): Utilities and tools for working with events created using either dependencies or watchers." + ] + }, + { + "cell_type": "markdown", + "id": "12e54858", + "metadata": {}, + "source": [ + "## Dependencies\n", + "\n", + "Param's `depends` decorator allows a programmer to express that a given computation \"depends\" on a certain set of parameters. For instance, if you have parameters whose values are interlinked, it's easy to express that relationship with `depends`:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3001f2d9", + "metadata": {}, + "outputs": [], + "source": [ + "import param\n", + "\n", + "class C(param.Parameterized):\n", + " _countries = {'Africa': ['Ghana', 'Togo', 'South Africa'],\n", + " 'Asia' : ['China', 'Thailand', 'Japan', 'Singapore'],\n", + " 'Europe': ['Austria', 'Bulgaria', 'Greece', 'Switzerland']}\n", + " \n", + " continent = param.Selector(default='Asia', objects=list(_countries.keys()))\n", + " country = param.Selector(objects=_countries['Asia'])\n", + " \n", + " @param.depends('continent', watch=True)\n", + " def _update_countries(self):\n", + " countries = self._countries[self.continent]\n", + " self.param['country'].objects = countries\n", + " if self.country not in countries:\n", + " self.country = countries[0]\n", + "\n", + "c = C()\n", + "c.country, c.param.country.objects" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "93e1c6e6", + "metadata": {}, + "outputs": [], + "source": [ + "c.continent='Africa'\n", + "c.country, c.param.country.objects" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8258470a", + "metadata": {}, + "outputs": [], + "source": [ + "c" + ] + }, + { + "cell_type": "markdown", + "id": "e2f371c2", + "metadata": {}, + "source": [ + "As you can see, here Param updates the allowed and current values for `country` whenever someone changes the `continent` parameter. This code relies on the dependency mechanism to make sure these parameters are kept appropriately synchronized:\n", + "\n", + "1. First, we set up the default continent but do not declare the `objects` and `default` for the `country` parameter. This is because this parameter is dependent on the `continent` and therefore it is easy to set up values that are inconsistent and makes it difficult to override the default continent since changes to both parameters need to be coordinated. \n", + "2. Next, if someone chooses a different continent, the list of countries allowed needs to be updated, so the method `_update_countries()` that (a) looks up the countries allowed for the current continent, (b) sets that list as the allowed objects for the `country` parameter, and (c) selects the first such country as the default country.\n", + "3. Finally, we expressed that the `_update_countries()` method depends on the `continent` parameter. We specified `watch=True` to direct Param to invoke this method immediately, whenever the value of `continent` changes. We'll see [examples of watch=False](#watch-false-dependencies) later. Importantly we also set `on_init=True`, which means that when instance is created the `self._update_countries()` method is automatically called setting up the `country` parameter appropriately. This avoids having to declare a `__init__` method to manually call the method ourselves and the potentially brittle process of setting up consistent defaults." + ] + }, + { + "cell_type": "markdown", + "id": "b14b37b6", + "metadata": {}, + "source": [ + "### Dependency specs\n", + "\n", + "The example above expressed a dependency of `_update_countries` on this object's `continent` parameter. A wide range of such dependency relationships can be specified:\n", + "\n", + "1. **Multiple dependencies**: Here we had only one parameter in the dependency list, but you can supply any number of dependencies (`@param.depends('continent', 'country', watch=True)`).\n", + "2. **Dependencies on nested parameters**: Parameters specified can either be on this class, or on nested Parameterized objects of this class. Parameters on this class are specified as the attribute name as a simple string (like `'continent'`). Nested parameters are specified as a dot-separated string (like `'handler.strategy.i'`, if this object has a parameter `handler`, whose value is an object `strategy`, which itself has a parameter `i`). If you want to depend on some arbitrary parameter elsewhere in Python, just create an `instantiate=False` (and typically read-only) parameter on this class to hold it, then here you can specify the path to it on _this_ object.\n", + "3. **Dependencies on metadata**: By default, dependencies are tied to a parameter's current value, but dependencies can also be on any of the declared metadata about the parameter (e.g. a method could depend on `country:constant`, triggering when someone changes whether that parameter is constant, or on `country:objects` (triggering when the objects list is replaced (not just changed in place as in appending). The available metadata is listed in the `__slots__` attribute of a Parameter object (e.g. \n", + "`p.param.continent.__slots__`). \n", + "4. **Dependencies on any nested param**: If you want to depend on _all_ the parameters of a nested object `n`, your method can depend on `'n.param'` (where parameter `n` has been set to a Parameterized object).\n", + "5. **Dependencies on a method name**: Often you will want to break up computation into multiple chunks, some of which are useful on their own and some which require other computations to have been done as prerequisites. In this case, your method can declare a dependency on another method (as a string name), which means that it will now watch everything that method watches, and will then get invoked after that method is invoked.\n", + "\n", + "We can see examples of all these dependency specifications in class `D` below:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6df85b16", + "metadata": {}, + "outputs": [], + "source": [ + "class D(param.Parameterized):\n", + " x = param.Number(7)\n", + " s = param.String(\"never\")\n", + " i = param.Integer(-5)\n", + " o = param.Selector(objects=['red', 'green', 'blue'])\n", + " n = param.ClassSelector(default=c, class_=param.Parameterized, instantiate=False) \n", + " \n", + " @param.depends('x', 's', 'n.country', 's:constant', watch=True)\n", + " def cb1(self):\n", + " print(f\"cb1 x={self.x} s={self.s} \"\n", + " f\"param.s.constant={self.param.s.constant} n.country={self.n.country}\")\n", + "\n", + " @param.depends('n.param', watch=True)\n", + " def cb2(self):\n", + " print(f\"cb2 n={self.n}\")\n", + "\n", + " @param.depends('x', 'i', watch=True)\n", + " def cb3(self):\n", + " print(f\"cb3 x={self.x} i={self.i}\")\n", + "\n", + " @param.depends('cb3', watch=True)\n", + " def cb4(self):\n", + " print(f\"cb4 x={self.x} i={self.i}\")\n", + "\n", + "d = D()\n", + "d" + ] + }, + { + "cell_type": "markdown", + "id": "80365d7f", + "metadata": {}, + "source": [ + "Here we have created an object `d` of type `D` with a unique ID like `D00003`. `d` has various parameters, including one nested Parameterized object in its parameter `n`. In this class, the nested parameter is set to our earlier object `c`, using `instantiate=False` to ensure that the value is precisely the same earlier object, not a copy of it. You can verify that it is the same object by comparing e.g. `name='C00002'` in the repr for the subobject in `d` to the name in the repr for `c` in the previous section; both should be e.g. `C00002`.\n", + "\n", + "Dependencies are stored declaratively so that they are accessible for other libraries to inspect and use. E.g. we can now examine the dependencies for the decorated callback method `cb1`:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c13bd79d", + "metadata": {}, + "outputs": [], + "source": [ + "dependencies = d.param.method_dependencies('cb1')\n", + "[f\"{o.inst.name}.{o.pobj.name}:{o.what}\" for o in dependencies]" + ] + }, + { + "cell_type": "markdown", + "id": "7548280e", + "metadata": {}, + "source": [ + "Here we can see that method `cb1` will be invoked for any value changes in `d`'s parameters `x` or `s`, for any value changes in `c`'s parameter `country`, and a change in the `constant` slot of `s`. These dependency relationships correspond to the specification `@param.depends('x', 's', 'n.country', 's:constant', watch=True)` above.\n", + "\n", + "Now, if we change `x`, we can see that Param invokes `cb1`:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "77caf9c1", + "metadata": {}, + "outputs": [], + "source": [ + "d.x = 5" + ] + }, + { + "cell_type": "markdown", + "id": "066453bf", + "metadata": {}, + "source": [ + "`cb3` and `cb4` are also invoked, because `cb3` depends on `x` as well, plus `cb4` depends on `cb3`, inheriting all of `cb3`'s dependencies.\n", + "\n", + "If we now change `c.country`, `cb1` will be invoked since `cb1` depends on `n.country`, and `n` is currently set to `c`:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "17394110", + "metadata": {}, + "outputs": [], + "source": [ + "c.country = 'Togo'" + ] + }, + { + "cell_type": "markdown", + "id": "477ab1d1", + "metadata": {}, + "source": [ + "As you can see, `cb2` is also invoked, because `cb2` depends on _all_ parameters of the subobject in `n`. \n", + "\n", + "`continent` is also a parameter on `c`, so `cb2` will also be invoked if you change `c.continent`. Note that changing `c.continent` itself invokes `c._update_countries()`, so in that case `cb2` actually gets invoked _twice_ (once for each parameter changed on `c`), along with `cb1` (watching `n.country`):" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "acc4c4cb", + "metadata": {}, + "outputs": [], + "source": [ + "c.continent = 'Europe'" + ] + }, + { + "cell_type": "markdown", + "id": "a973b325", + "metadata": {}, + "source": [ + "Changing metadata works just the same as changing values. Because `cb1` depends on the `constant` slot of `s`, it is invoked when that slot changes:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a6403a93", + "metadata": {}, + "outputs": [], + "source": [ + "d.param.s.constant = True" + ] + }, + { + "cell_type": "markdown", + "id": "68c82e25", + "metadata": {}, + "source": [ + "Importantly, if we replace a sub-object on which we have declared dependencies, Param automatically rebinds the dependencies to the new object:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f6195bdd", + "metadata": {}, + "outputs": [], + "source": [ + "d.n = C()" + ] + }, + { + "cell_type": "markdown", + "id": "af05eb1f", + "metadata": {}, + "source": [ + "Note that if the values of the dependencies on the old and new object are the same, no event is fired. \n", + "\n", + "Additionally the previously bound sub-object is now no longer connected:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9d52086e", + "metadata": {}, + "outputs": [], + "source": [ + "c.continent = 'Europe'" + ] + }, + { + "cell_type": "markdown", + "id": "6e4d5b80", + "metadata": {}, + "source": [ + "### `watch=False` dependencies\n", + "\n", + "The previous examples all supplied `watch=True`, indicating that Param itself should watch for changes in the dependency and invoke that method when a dependent parameter is set. If `watch=False` (the default), `@param.depends` declares that such a dependency exists, but does not automatically invoke it. `watch=False` is useful for setting up code for a separate library like [Panel](https://panel.holoviz.org) or [HoloViews](https://holoviews.org) to use, indicating which parameters the external library should watch so that it knows when to invoke the decorated method. Typically, you'll want to use `watch=False` when that external library needs to do something with the return value of the method (a functional approach), and use `watch=True` when the function is [side-effecty](https://en.wikipedia.org/wiki/Side_effect_(computer_science)), i.e. having an effect just from running it, and not normally returning a value.\n", + "\n", + "For instance, consider this Param class with methods that return values to display:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7f1ebe63", + "metadata": {}, + "outputs": [], + "source": [ + "class Mul(param.Parameterized):\n", + " a = param.Number(5, bounds=(-100, 100))\n", + " b = param.Number(-2, bounds=(-100, 100))\n", + "\n", + " @param.depends('a', 'b')\n", + " def view(self):\n", + " return str(self.a*self.b)\n", + "\n", + " def view2(self):\n", + " return str(self.a*self.b)\n", + "\n", + "prod = Mul(name='Multiplier')" + ] + }, + { + "cell_type": "markdown", + "id": "00ff51ea", + "metadata": {}, + "source": [ + "You could run this code manually:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fc51ed2b", + "metadata": {}, + "outputs": [], + "source": [ + "prod.a = 7\n", + "prod.b = 10\n", + "prod.view()" + ] + }, + { + "cell_type": "markdown", + "id": "50ab0942", + "metadata": {}, + "source": [ + "Or you could pass the parameters and the `view` method to Panel, and let Panel invoke it as needed by following the dependency chain:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "05f1bb0d", + "metadata": {}, + "outputs": [], + "source": [ + "import panel as pn\n", + "pn.extension()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "050b268a", + "metadata": {}, + "outputs": [], + "source": [ + "pn.Row(prod.param, prod.view)" + ] + }, + { + "cell_type": "markdown", + "id": "acda7cc7", + "metadata": {}, + "source": [ + "Panel creates widgets for the parameters, runs the `view` method with the default values of those parameters, and displays the result. As long as you have a live Python process running (not just a static HTML export of this page as on param.holoviz.org), Panel will then watch for changes in those parameters due to the widgets and will re-execute the `view` method to update the output whenever one of those parameters changes. Using the dependency declarations, Panel is able to do all this without ever having to be told separately which parameters there are or what dependency relationships there are. \n", + "\n", + "How does that work? A library like Panel can simply ask Param what dependency relationships have been declared for the method passed to it:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3536291d", + "metadata": {}, + "outputs": [], + "source": [ + "[o.name for o in prod.param.method_dependencies('view')]" + ] + }, + { + "cell_type": "markdown", + "id": "899a41e8", + "metadata": {}, + "source": [ + "Note that in this particular case the `depends` decorator could have been omitted, because Param conservatively assumes that any method _could_ read the value of any parameter, and thus if it has no other declaration from the user, the dependencies are assumed to include _all_ parameters (including `name`, even though it is constant):" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a8bef58c", + "metadata": {}, + "outputs": [], + "source": [ + "[o.name for o in prod.param.method_dependencies('view2')]" + ] + }, + { + "cell_type": "markdown", + "id": "f8383036", + "metadata": {}, + "source": [ + "Conversely, if you want to declare that a given method does not depend on any parameters at all, you can use `@param.depends()`. \n", + "\n", + "Be sure not to set `watch=True` for dependencies for any method you pass to an external library like Panel to handle, or else that method will get invoked _twice_, once by Param itself (discarding the output) and once by the external library (using the output). Typically you will want `watch=True` for a side-effecty function or method (typically not returning a value), and `watch=False` (the default) for a function or method with a return value, and you'll need an external library to do something with that return value." + ] + }, + { + "cell_type": "markdown", + "id": "1169f3b6", + "metadata": {}, + "source": [ + "### `@param.depends` with function objects\n", + "\n", + "The `depends` decorator can also be used with bare functions, in which case the specification should be an actual Parameter object, not a string. The function will be called with the parameter(s)'s value(s) as positional arguments:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "60a085b7", + "metadata": {}, + "outputs": [], + "source": [ + "@param.depends(c.param.country, d.param.i, watch=True)\n", + "def g(country, i):\n", + " print(f\"g country={country} i={i}\")\n", + "\n", + "c.country = 'Greece'" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a7105a92", + "metadata": {}, + "outputs": [], + "source": [ + "d.i = 6" + ] + }, + { + "cell_type": "markdown", + "id": "cd198a2e", + "metadata": {}, + "source": [ + "Here you can see that in addition to the classmethods starting with `cb` previously set up to depend on the country, setting `c`'s `country` parameter or `d`'s `i` parameter now also invokes function `g`, passing in the current values of the parameters it depends on whenever the function gets invoked. `g` can then make a side effect happen such as updating any other data structure it can access that needs to be changed when `country` or `i` changes. \n", + "\n", + "Using `@param.depends(..., watch=False)` with a function allows providing bound standalone functions to an external library for display, just as in the `.view` method above.\n", + "\n", + "Of course, you can still invoke `g` with your own explicit arguments, which does not invoke any watching mechanisms:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c4e160c1", + "metadata": {}, + "outputs": [], + "source": [ + "g('USA', 7)" + ] + }, + { + "cell_type": "markdown", + "id": "00370f00", + "metadata": {}, + "source": [ + "## Watchers\n", + "\n", + "The `depends` decorator is built on Param's lower-level `.param.watch` interface, registering the decorated method or function as a `Watcher` object associated with those parameter(s). If you're building or using a complex library like Panel, you can use the low-level Parameter watching interface to set up arbitrary chains of watchers to respond to parameter value or metadata setting:\n", + "\n", + "- `obj.param.watch(fn, parameter_names, what='value', onlychanged=True, queued=False, precedence=0)`:
Create and register a `Watcher` that will invoke the given callback `fn` when the `what` item (`value` or one of the Parameter's slots) is set (or more specifically, changed, if `onlychanged=True`). If `queued=True`, delays calling any events triggered during this callback's execution until all processing of the current events has been completed (breadth-first Event processing rather than the default depth-first processing). The `precedence` declares a precedence level for the Watcher that determines the priority with which the callback is executed. Lower precedence levels are executed earlier. Negative precedences are reserved for internal Watchers, i.e. those set up by `param.depends`. The `fn` will be invoked with one or more `Event` objects that have been triggered, as positional arguments. Returns a `Watcher` object, e.g. for use in `unwatch`.\n", + "\n", + "- `obj.param.watch_values(fn, parameter_names, what='value', onlychanged=True, queued=False, precedence=0)`:
Easier-to-use version of `obj.param.watch` specific to watching for changes in parameter values. Same as `watch`, but hard-codes `what='value'` and invokes the callback `fn` using keyword arguments _param_name_=_new_value_ rather than with a positional-argument list of `Event` objects.\n", + "\n", + "- `obj.param.unwatch(watcher)`:
Remove the given `Watcher` (typically obtained as the return value from `watch` or `watch_values`) from those registered on this `obj`.\n", + "\n", + "To see how to use `watch` and `watch_values`, let's make a class with parameters `a` and `b` and various watchers with corresponding callback methods:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9f076d1b", + "metadata": {}, + "outputs": [], + "source": [ + "def e(e):\n", + " return f\"(event: {e.name} changed from {e.old} to {e.new})\"\n", + "\n", + "class P(param.Parameterized):\n", + " a = param.Integer(default=0)\n", + " b = param.Integer(default=0)\n", + " \n", + " def __init__(self, **params):\n", + " super().__init__(**params)\n", + " self.param.watch(self.run_a1, ['a'], queued=True, precedence=2)\n", + " self.param.watch(self.run_a2, ['a'], precedence=1)\n", + " self.param.watch(self.run_b, ['b'])\n", + "\n", + " def run_a1(self, event):\n", + " self.b += 1\n", + " print('a1', self.a, e(event))\n", + "\n", + " def run_a2(self, event):\n", + " print('a2', self.a, e(event))\n", + "\n", + " def run_b(self, event):\n", + " print('b', self.b, e(event))\n", + " \n", + "p = P()\n", + "\n", + "p.a = 1" + ] + }, + { + "cell_type": "markdown", + "id": "6cdbd8e5", + "metadata": {}, + "source": [ + "Here, we have set up three Watchers, each invoking a method on `P` when either `a` or `b` changes. The first Watcher invokes `run_a1` when `a` changes, and in turn `run_a1` changes `b`. Since `queued=True` for `run_a1`, `run_b` is not invoked while `run_a1` executes, but only later once both `run_a1` and `run_a2` have completed (since both Watchers were triggered by the original event `p.a=1`).\n", + "\n", + "Additionally we have set a higher `precedence` value for `run_a1` which results in it being executed **after** `run_a2`.\n", + "\n", + "Here we're using data from the `Event` objects given to each callback to see what's changed; try `help(param.parameterized.Event)` for details of what is in these objects (and similarly try the help for `Watcher` (returned by `watch`) or `PInfo` (returned by `.param.method_dependencies`))." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cef96eae", + "metadata": {}, + "outputs": [], + "source": [ + "#help(param.parameterized.Event)\n", + "#help(param.parameterized.Watcher)\n", + "#help(param.parameterized.PInfo)" + ] + }, + { + "cell_type": "markdown", + "id": "c06d1a13", + "metadata": {}, + "source": [ + "## Using dependencies and watchers\n", + "\n", + "Whether you use the `watch` or the `depends` approach, Param will store a set of `Watcher` objects on each `Parameterized` object that let it manage and process `Event`s. Param provides various context managers, methods, and Parameters that help you work with Watchers and Events:\n", + "\n", + "- [`batch_call_watchers`](#batch-call-watchers): context manager accumulating and eliding multiple Events to be applied on exit from the context \n", + "- [`discard_events`](#discard-events): context manager silently discarding events generated while in the context\n", + "- [`.param.trigger`](#param-trigger): method to force creation of an Event for this Parameter's Watchers without a corresponding change to the Parameter\n", + "- [`.param.watchers`](#param-watchers): writable property to access the instance watchers\n", + "- [Event Parameter](#event-parameter): Special Parameter type providing triggerable transient Events (like a momentary push button)\n", + "- [Async executor](#async-executor): Support for asynchronous processing of Events, e.g. for interfacing to external servers\n", + "\n", + "Each of these will be described in the following sections." + ] + }, + { + "cell_type": "markdown", + "id": "9356f733", + "metadata": {}, + "source": [ + "### `batch_call_watchers`\n", + "\n", + "Context manager that accumulates parameter changes on the supplied object and dispatches them all at once when the context is exited, to allow multiple changes to a given parameter to be accumulated and short-circuited, rather than prompting serial changes from a batch of parameter setting:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "905456c3", + "metadata": {}, + "outputs": [], + "source": [ + "with param.parameterized.batch_call_watchers(p):\n", + " p.a = 2\n", + " p.a = 3\n", + " p.a = 1\n", + " p.a = 5" + ] + }, + { + "cell_type": "markdown", + "id": "9c25515a", + "metadata": {}, + "source": [ + "Here, even though `p.a` is changed four times, each of the watchers of `a` is executed only once, with the final value. One of those events then changes `b`, so `b`'s watcher is also executed once.\n", + "\n", + "If we set `b` explicitly, `b`'s watcher will be invoked twice, once for the explicit setting of `b`, and once because of the code `self.b += 1`:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6c7fe2df", + "metadata": {}, + "outputs": [], + "source": [ + "with param.parameterized.batch_call_watchers(p):\n", + " p.a = 2\n", + " p.b = 8\n", + " p.a = 3\n", + " p.a = 1\n", + " p.a = 5" + ] + }, + { + "cell_type": "markdown", + "id": "1deb1709", + "metadata": {}, + "source": [ + "If all you need to do is set a batch of parameters, you can use `.update` instead of `batch_call_watchers`, which has the same underlying batching mechanism:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e511a92a", + "metadata": {}, + "outputs": [], + "source": [ + "p.param.update(a=9,b=2)" + ] + }, + { + "cell_type": "markdown", + "id": "acc97f01", + "metadata": {}, + "source": [ + "### `discard_events`\n", + "\n", + "Context manager that discards any events within its scope that are triggered on the supplied parameterized object. Useful for making silent changes to dependent parameters, e.g. in a setup phase. If your dependencies are meant to ensure consistency between parameters, be careful that your manual changes in this context don't put the object into an inconsistent state!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cf129b7c", + "metadata": {}, + "outputs": [], + "source": [ + "with param.parameterized.discard_events(p):\n", + " p.a = 2\n", + " p.b = 9" + ] + }, + { + "cell_type": "markdown", + "id": "ffc9a462", + "metadata": {}, + "source": [ + "(Notice that none of the callbacks is invoked, despite all the Watchers on `p.a` and `p.b`.)" + ] + }, + { + "cell_type": "markdown", + "id": "67437fe6", + "metadata": {}, + "source": [ + "### `.param.trigger`\n", + "\n", + "Usually, a Watcher will be invoked only when a parameter is set (and only if it is changed, by default). What if you want to trigger a Watcher in other cases? For instance, if a parameter value is a mutable container like a list and you add or change an item in that container, Param's `set` method will never be invoked, because in Python the container itself is not changed when the contents are changed. In such cases, you can trigger a watcher explicitly, using `.param.trigger(*param_names)`. Triggering does not affect parameter values, apart from the special parameters of type Event (see [below](#Event-Parameter:)).\n", + "\n", + "For instance, if you set `p.b` to the value it already has, no callback will normally be invoked:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c2b06db2", + "metadata": {}, + "outputs": [], + "source": [ + "p.b = p.b" + ] + }, + { + "cell_type": "markdown", + "id": "9fb9a5a8", + "metadata": {}, + "source": [ + "But if you explicitly trigger parameter `b` on `p`, `run_b` will be invoked, even though the value of `b` is not changing:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b086d010", + "metadata": {}, + "outputs": [], + "source": [ + "p.param.trigger('b')" + ] + }, + { + "cell_type": "markdown", + "id": "621e183e", + "metadata": {}, + "source": [ + "If you trigger `a`, the usual series of chained events will be triggered, including changing `b`:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "827ef750", + "metadata": {}, + "outputs": [], + "source": [ + "p.param.trigger('a')" + ] + }, + { + "cell_type": "markdown", + "id": "fc3cb5ba", + "metadata": {}, + "source": [ + "### `.param.watchers`\n", + "\n", + "For more advanced purposes it can be useful to inspect all the watchers set up on an instance, in which case you can use `inst.param.watchers` to obtain a dictionary with the following structure: `{parameter_name: {what: [Watcher(), ...], ...}, ...}`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0b2ae598", + "metadata": {}, + "outputs": [], + "source": [ + "p.param.watchers" + ] + }, + { + "cell_type": "markdown", + "id": "42ffa0a0", + "metadata": {}, + "source": [ + "### `Event` Parameter\n", + "\n", + "An Event Parameter is a special Parameter type whose value is intimately linked to the triggering of events for Watchers to consume. Event has a Boolean value, which when set to `True` triggers the associated watchers (as any Parameter does) but then is automatically set back to `False`. \n", + "\n", + "Conversely, if events are triggered directly on a `param.Event` via `.trigger`, the value is transiently set to True (so that it's clear which of many parameters being watched may have changed), then restored to False when the triggering completes. An Event parameter is thus like a momentary switch or pushbutton with a transient True value that normally serves only to launch some other action (e.g. via a `param.depends` decorator or a watcher), rather than encapsulating the action itself as `param.Action` does. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8498624d", + "metadata": {}, + "outputs": [], + "source": [ + "class Q(param.Parameterized):\n", + " e = param.Event()\n", + " \n", + " @param.depends('e', watch=True)\n", + " def callback(self):\n", + " print(f'e=={self.e}')\n", + " \n", + "q = Q()\n", + "q.e = True" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "317b053e", + "metadata": {}, + "outputs": [], + "source": [ + "q.e" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b423aa8b", + "metadata": {}, + "outputs": [], + "source": [ + "q.param.trigger('e')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bb5b83ae", + "metadata": {}, + "outputs": [], + "source": [ + "q.e" + ] + }, + { + "cell_type": "markdown", + "id": "8f17a138", + "metadata": {}, + "source": [ + "### Async executor\n", + "\n", + "Param's events and callbacks described above are all synchronous, happening in a clearly defined order where the processing of each function blocks all other processing until it is completed. Watchers can also be used with the Python3 asyncio [`async`/`await`](https://docs.python.org/3/library/asyncio-task.html) support to operate asynchronously. To do this, you can define `param.parameterized.async_executor` with an asynchronous executor that schedules tasks on an event loop from e.g. Tornado or the [asyncio](https://docs.python.org/3/library/asyncio.html) library, which will allow you to use coroutines and other asynchronous functions as `.param.watch` callbacks.\n", + "\n", + "As an example, you can use the Tornado IOLoop underlying this Jupyter Notebook by putting events on the event loop and watching for results to accumulate:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "03ece21a", + "metadata": {}, + "outputs": [], + "source": [ + "import param, asyncio, aiohttp\n", + "from tornado.ioloop import IOLoop\n", + "\n", + "param.parameterized.async_executor = IOLoop.current().add_callback\n", + "\n", + "class Downloader(param.Parameterized):\n", + " url = param.String()\n", + " results = param.List()\n", + " \n", + " def __init__(self, **params):\n", + " super().__init__(**params)\n", + " self.param.watch(self.fetch, ['url'])\n", + "\n", + " async def fetch(self, event):\n", + " async with aiohttp.ClientSession() as session:\n", + " async with session.get(event.new) as response:\n", + " img = await response.read()\n", + " self.results.append((event.new, img))\n", + "\n", + "f = Downloader()\n", + "n = 7\n", + "for index in range(n):\n", + " f.url = f\"https://picsum.photos/800/300?image={index}\"\n", + "\n", + "f.results" + ] + }, + { + "cell_type": "markdown", + "id": "4744d8c7", + "metadata": {}, + "source": [ + "When you execute the above cell, you will normally get `[]`, indicating that there are not yet any results available. \n", + "\n", + "What the code does is to request 10 different images from an image site by repeatedly setting the `url` parameter of `Downloader` to a new URL. Each time the `url` parameter is modified, because of the `self.param.watch` call, the `self.fetch` callback is invoked. Because it is marked `async` and uses `await` internally, the method call returns without waiting for results to be available. Once the `await`ed results are available, the method continues with its execution and a tuple (_image_name_, _image_data_) is added to the `results` parameter.\n", + "\n", + "If you need to have all the results available (and have an internet connection!), you can wait for them:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "38da7bb2", + "metadata": {}, + "outputs": [], + "source": [ + "print(\"Waiting: \", end=\"\")\n", + "while len(f.results)" + ] + }, + { + "cell_type": "markdown", + "id": "3683dec7", + "metadata": {}, + "source": [ + "## Parameter value instantiation\n", + "\n", + "So much of the parameter metadata is there to help you control whether and how the parameter value is instantiated on Parameterized objects as they are created or new Parameterized subclasses as they are defined. Depending on how you want to use that Parameter and what values it might take, controlling instantiation can be very important when mutable values are involved. While the default behavior shown above is appropriate for **immutable attributes**, what happens if the value (unlike Python strings) is mutable? Things get a lot more complex." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b9fa3c69", + "metadata": {}, + "outputs": [], + "source": [ + "s = [1, 2, 3]\n", + "\n", + "class C(Parameterized):\n", + " s1 = Parameter(s, doc=\"A sequence\")\n", + " s2 = Parameter(s, doc=\"Another sequence\")\n", + "\n", + "c = C()" + ] + }, + { + "cell_type": "markdown", + "id": "fe928bac", + "metadata": {}, + "source": [ + "Here, both parameters `s1` and `s2`, on both `A` and `B` effectively point to the same underlying sequence `s`:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ba3863a5", + "metadata": {}, + "outputs": [], + "source": [ + "c.s1 is c.s2" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0b9004be", + "metadata": {}, + "outputs": [], + "source": [ + "s[1] *= 5" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "81f40ddf", + "metadata": {}, + "outputs": [], + "source": [ + "s" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e69157b7", + "metadata": {}, + "outputs": [], + "source": [ + "c.s1" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "344bae37", + "metadata": {}, + "outputs": [], + "source": [ + "c.s1[2] = 'a'" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "baf5b9f6", + "metadata": {}, + "outputs": [], + "source": [ + "c.s1" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5c87a5d6", + "metadata": {}, + "outputs": [], + "source": [ + "c.s2" + ] + }, + { + "cell_type": "markdown", + "id": "08324f49", + "metadata": {}, + "source": [ + "As you can see, there is only one actual sequence here, and `s`, `s1`, and `s2` all point to it. In some cases such behavior is desirable, e.g. if the mutable object is a specific global list (e.g. a set of search paths) with a unique identity and all of the parameters are meant to point to that specific item. In other cases, it's the contents of the mutable item that are important, and no sharing of contents is intended. Luckily, Param supports that case as well, if you provide `instantiate=True` (default is `False`):" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5c92d85f", + "metadata": {}, + "outputs": [], + "source": [ + "s = [1,2,3]\n", + "\n", + "class D(Parameterized):\n", + " s1 = Parameter(default=s, doc=\"A sequence\", instantiate=True)\n", + " s2 = Parameter(default=s, doc=\"Another sequence\", instantiate=True)\n", + "\n", + "d = D()" + ] + }, + { + "cell_type": "markdown", + "id": "325b9bbe", + "metadata": {}, + "source": [ + "Now, parameters `s1` and `s2` point to their own copies of the sequence, independent of each other and of the original argument `s`:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4c245a25", + "metadata": {}, + "outputs": [], + "source": [ + "d.s1 is d.s2" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "509c07ac", + "metadata": {}, + "outputs": [], + "source": [ + "s *= 2" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "311dbcba", + "metadata": {}, + "outputs": [], + "source": [ + "s" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9e5c5336", + "metadata": {}, + "outputs": [], + "source": [ + "d.s1" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f9d142d7", + "metadata": {}, + "outputs": [], + "source": [ + "d.s1[2] = 'a'" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3d9a12f0", + "metadata": {}, + "outputs": [], + "source": [ + "d.s2" + ] + }, + { + "cell_type": "markdown", + "id": "3792939f", + "metadata": {}, + "source": [ + "Of course, copying the data into each instance like that costs memory, and moreover prevents controlling all instances at once by setting a class attribute as we saw earlier, which is why `instantiate` is not True by default. As a rule of thumb, set `instantiate=True` if and only if (a) your Parameter can take mutable values, and (b) you want those values to be independent between Parameterized instances." + ] + }, + { + "cell_type": "markdown", + "id": "6cfed7ae", + "metadata": {}, + "source": [ + "## Parameter object instantiation\n", + "\n", + "`instantiate` controls how parameter _values_ behave, but similar issues arise for Parameter _objects_, which offer similar control via the `per_instance` metadata declaration. `per_instance` (`True` by default) provides a logically distinct Parameter object for every Parameterized instance, allowing each such instance to have different metadata for that parameter. For example, we can set the label separately for each instance without clobbering each other:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2f5af5da", + "metadata": {}, + "outputs": [], + "source": [ + "d1 = D()\n", + "d2 = D()\n", + "d1.param.s1.label = \"sequence 1\"\n", + "d2.param.s1.label = \"(sequence 1)\"\n", + "d2.param.s1.label" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9f224f3b", + "metadata": {}, + "outputs": [], + "source": [ + "d1.param.s1.label" + ] + }, + { + "cell_type": "markdown", + "id": "5ce34483", + "metadata": {}, + "source": [ + "This capability is useful for situations with dynamically updated metadata, e.g. if you need setting one parameter's value (e.g. 'Continent') to change the allowed values of another parameter (e.g. 'Country'). The underlying Parameter objects are copied lazily (only when actually changed), so that objects are not actually multiplied unless necessary. If you do want parameters to share a single Parameter object so that you can control its behavior globally, you can achieve that with `per_instance=False`, though the effects can be confusing in the same way as `instantiate=True` for mutable objects (above):" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "787e9813", + "metadata": {}, + "outputs": [], + "source": [ + "class E(Parameterized):\n", + " a = Parameter(default=3.14, label=\"pi\", per_instance=False)\n", + "\n", + "e1 = E()\n", + "e2 = E()\n", + "e2.param.a.label = \"Pie\"\n", + "e1.param.a.label" + ] + }, + { + "cell_type": "markdown", + "id": "c2e3d4a7", + "metadata": {}, + "source": [ + "## Instantiating with shared parameters\n", + "\n", + "When creating a large collection of Parameterized objects of the same type, the overhead of having separate parameters for each object can be significant. If you want, you can create the objects to share parameter values for efficiency, and also so that you can easily change a value on all such objects at the same time. \n", + "\n", + "As an example, let's say you've defined a Parameter value to be independent, such that changing one instance's value will not affect the others:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5013fe69", + "metadata": {}, + "outputs": [], + "source": [ + "class S(param.Parameterized):\n", + " l = Parameter(default=[1,2,3], instantiate=True)\n", + "\n", + "ss = [S() for i in range(10)]\n", + "ss[0].l[2] = 5\n", + "ss[1].l" + ] + }, + { + "cell_type": "markdown", + "id": "6c7195fd", + "metadata": {}, + "source": [ + "Here changing the value of `l` on `ss[0]` doesn't affect `ss[1]` or any other instances.\n", + "\n", + "What if you as a user of this class are creating a very large number of similar objects and actually do want them to share the same parameter value, either to save memory or to make it easy to change all of their values at once? In that case you can use the context manager `shared_parameters`, and any Parameterized objects created within that context will share parameter values, such that changing one of them will affect all of them:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "37e160d4", + "metadata": {}, + "outputs": [], + "source": [ + "with param.shared_parameters():\n", + " ps = [S() for i in range(10)]\n", + " \n", + "ps[0].l[2] = 5\n", + "ps[1].l" + ] + }, + { + "cell_type": "markdown", + "id": "ed4e296f", + "metadata": {}, + "source": [ + "This approach can provide significant speedup and memory savings in certain cases, but should only be used for good reasons, since it can cause confusion for any code expecting instances to be independent as they have been declared." + ] + }, + { + "cell_type": "markdown", + "id": "678b7a0e", + "metadata": {}, + "source": [ + "## Displaying Parameterized objects\n", + "\n", + "Most of the important behavior of Parameterized is to do with instantiation, getting, and setting, as described above. Parameterized also provides a few public methods for creating string representations of the Parameterized object and its parameters:\n", + "\n", + "- `Parameterized.__str__()`: A concise, non-executable representation of the name and class of this object\n", + "- `Parameterized.__repr__()`: A representation of this object and its parameter values as if it were Python code calling the constructor (`classname(parameter1=x,parameter2=y,...)`)\n", + "- `Parameterize.param._repr_html_()`: A rich HTML representation of the object with its parameters listed in a table together with their metadata.\n", + "- `Parameterized.param.pprint()`: Customizable, hierarchical pretty-printed representation of this Parameterized and (recursively) any of its parameters that are Parameterized objects. See [Serialization and Persistence](Serialization_and_Persistence.ipynb) for details on customizing `pprint`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0a1521ba", + "metadata": {}, + "outputs": [], + "source": [ + "import param\n", + "\n", + "class Q(param.Parameterized):\n", + " a = param.Number(default=39, bounds=(0,50), doc='Number a')\n", + " b = param.String(default=\"str\", doc='A string')\n", + "\n", + "class P(Q):\n", + " c = param.ClassSelector(default=Q(), class_=Q, doc='An instance of Q')\n", + " e = param.ClassSelector(default=param.Parameterized(), class_=param.Parameterized, doc='A Parameterized instance')\n", + " f = param.Range(default=(0,1), doc='A range')\n", + "\n", + "p = P(f=(2,3), c=P(f=(42,43)), name=\"demo\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0b0d5b84", + "metadata": {}, + "outputs": [], + "source": [ + "p.__str__()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e119e92a", + "metadata": {}, + "outputs": [], + "source": [ + "p.__repr__()" + ] + }, + { + "cell_type": "markdown", + "id": "799c1eeb-71c2-40a3-ad06-fd3ed8eda501", + "metadata": {}, + "source": [ + "The HTML representation of a `Parameterized` instance or class is displayed when you call `.param` in a Notebook." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4c17a53b-3acc-4e6e-ab93-e5d09728e1c5", + "metadata": {}, + "outputs": [], + "source": [ + "p.param" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "64628d11-7f2c-4718-bd8a-7a381e282047", + "metadata": {}, + "outputs": [], + "source": [ + "P.param" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2ed3a3f0", + "metadata": {}, + "outputs": [], + "source": [ + "p.param.pprint(separator=\"\\n\")" + ] + }, + { + "cell_type": "markdown", + "id": "b0acf461", + "metadata": {}, + "source": [ + "Notice that in the case of a circular reference (`p.c = P(c=p)`) the representation will show an ellipsis (`...`) rather than recursively printing the subobject:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "22b09e5d", + "metadata": {}, + "outputs": [], + "source": [ + "p.c=P(c=p)\n", + "p.param.pprint()" + ] + }, + { + "cell_type": "markdown", + "id": "3830ace8", + "metadata": {}, + "source": [ + "## Parameterized namespace\n", + "\n", + "Param allows you to create Parameterized objects by inheriting from the `Parameterized` base class. Param has evolved over time to reduce its footprint and reserve as few as possible attributes on this namespace, to reduce the risk of name clashes and allow you to freely define your attribute names. Param reserves a few names that are described below, make sure not to override, unless it is stated it is allowed:\n", + "\n", + "- Public attributes:\n", + " - `name`: Parameterized classes and instances have a name `String` Parameter, that by default is set to the class name when accessed from the class and to the class name appended with a 5 digit when accessed from the instance. You can override this Parameter by your own `String` Parameter if you need to.\n", + " - `param`: Property that helps keep the Parameterized namespace clean and disambiguate between Parameter objects and parameter values, it gives access to a namespace that offers various methods (see the section below) to update and inspect the Parameterized object at hand.\n", + "- Private attributes:\n", + " - `_param__parameters`: Store the object returned by `.param` on the class\n", + " - `_param__private`: Store various internal data on Parameterized class and instances\n", + " - `_param_watchers` (deprecated in Param 2.0 and to be removed soon): Store a dictionary of instance watchers" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "01759e1b", + "metadata": {}, + "outputs": [], + "source": [ + "class P(param.Parameterized):\n", + " a = param.Number()\n", + " b = param.String()\n", + "\n", + "p = P()\n", + "print(f'{P.name=}, {p.name=}')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e802c7c7", + "metadata": {}, + "outputs": [], + "source": [ + "def namespace(obj):\n", + " return [o for o in dir(obj) if not o.startswith('__')]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5c702205", + "metadata": {}, + "outputs": [], + "source": [ + "namespace(P)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b74fb157", + "metadata": {}, + "outputs": [], + "source": [ + "namespace(p)" + ] + }, + { + "cell_type": "markdown", + "id": "23979d82", + "metadata": {}, + "source": [ + "## Other Parameterized methods\n", + "\n", + "Like `.param.pprint`, the remaining \"utility\" or convenience methods available for a `Parameterized` class or object are provided via the `.param` subobject:\n", + "\n", + "- `.param.update(**kwargs)`: Set parameter values from the given `param=value` keyword arguments (or a dict or iterable), delaying watching and dependency handling until all have been updated. `.param.update` can also be used as a context manager to temporarily set values, that are restored to their original values when the context manager exits." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1779f544", + "metadata": {}, + "outputs": [], + "source": [ + "p.param.update(a=0, b='start');\n", + "print(p.a, p.b)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f1508201", + "metadata": {}, + "outputs": [], + "source": [ + "with p.param.update(a=1, b='temp'):\n", + " print(f'In the context manager: {p.a=}, {p.b=}')\n", + "print(f'After the context manager exits: {p.a=}, {p.b=}')" + ] + }, + { + "cell_type": "markdown", + "id": "0b9e1d85", + "metadata": {}, + "source": [ + "- `.param.values(onlychanged=False)`: A dict of name,value pairs for all parameters of this object" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fd7f0eca", + "metadata": {}, + "outputs": [], + "source": [ + "p.param.values()" + ] + }, + { + "cell_type": "markdown", + "id": "244a17d0", + "metadata": {}, + "source": [ + "- `.param.objects(instance=True)`: Parameter objects of this instance or class" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1baf4823", + "metadata": {}, + "outputs": [], + "source": [ + "p.param.objects()" + ] + }, + { + "cell_type": "markdown", + "id": "1c5085ea", + "metadata": {}, + "source": [ + "\n", + "- `.param.add_parameter(param_name,param_obj)`: Dynamically add a new Parameter to this object's class\n", + "- `.param.get_value_generator(name)`: Returns the underlying value-generating callable for this parameter, or the underlying static value if none\n", + "- `.param.force_new_dynamic_value(name)`: For a Dynamic parameter, generate a new value and return it\n", + "- `.param.inspect_value(name)`: For a Dynamic parameter, return the current value of the named attribute without modifying it.\n" + ] + }, + { + "cell_type": "markdown", + "id": "3e8ab618", + "metadata": {}, + "source": [ + "## Specialized Parameter types\n", + "\n", + "As you can see above, a `Parameter` provides a lot of power already on its own, but in practice you will want to use much more specific parameter types that reject invalid inputs and keep your code clean and simple. A specialized Parameter acts as a \"contract\" with the users of the code you write, declaring and defending precisely what configuration is allowed and how to achieve it. If you need to accept specific inputs like that but don't add an appropriate Parameter type, you'll be stuck adding exceptions and validation code throughout your codebase, whereas anything you can express at the Parameter level will be enforced automatically without any further checks or code.\n", + "\n", + "For instance, what if you want to accept a numeric parameter, but (for some reason) can only accept numbers that are even integers? You'll need a custom Parameter class to express a restriction like that. In this case you can do it by overriding the `_validate_value` method of the `Parameter` class:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "89c1d341", + "metadata": {}, + "outputs": [], + "source": [ + "import numbers\n", + "\n", + "class EvenInteger(param.Parameter):\n", + " \"\"\"Integer Parameter that must be even\"\"\"\n", + "\n", + " def _validate_value(self, val, allow_None):\n", + " super()._validate_value(val, allow_None)\n", + " if not isinstance(val, numbers.Number):\n", + " raise ValueError(\n", + " f\"EvenInteger parameter {self.name!r} must be a number, not {val!r}.\"\n", + " )\n", + " \n", + " if not (val % 2 == 0):\n", + " raise ValueError(\n", + " f\"EvenInteger parameter {self.name!r} must be even, not {val!r}.\"\n", + " )\n", + "\n", + "class P(param.Parameterized):\n", + " n = param.Number()\n", + " b = EvenInteger()\n", + " \n", + "p=P()\n", + "P(n=5, b=4)\n", + "P(b=4, n=5, name='P00003')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "80fbb171", + "metadata": {}, + "outputs": [], + "source": [ + "with param.exceptions_summarized():\n", + " P(n=5, b=\"four\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "980b932b", + "metadata": {}, + "outputs": [], + "source": [ + "with param.exceptions_summarized():\n", + " P(n=5, b=5)" + ] + }, + { + "cell_type": "markdown", + "id": "cc659490", + "metadata": {}, + "source": [ + "Luckily, you don't often need to write a custom Parameter class like this, because the most common cases are already provided in Param, as listed in the [Parameter Types](Parameter_Types.ipynb) manual. If you need something more specific than the existing types, start with the one that comes closest to restricting its value to the desired set of values without excluding any allowable values. In this case all integer powers of 2 are also integers, so you'd start with `param.Integer` rather than `param.Parameterized` as above. You can then make a new subclass and add validation as above to further restrict the values to precisely what you allow. Here if you inherited from `param.Integer` you would no longer need to check if the input is a number, as `param.Integer` already does that as long as you call `super` as above. Your custom type can override any aspects of the Parameter if needed, e.g. to accept different items in the constructor, store additional data, add additional constraints, and so on. The existing Parameter types in `param/__init__.py` act as a rich source of examples for you to start with and crib from." + ] + } + ], + "metadata": { + "language_info": { + "name": "python", + "pygments_lexer": "ipython3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/_sources/user_guide/Reactive_Expressions.ipynb.txt b/_sources/user_guide/Reactive_Expressions.ipynb.txt new file mode 100644 index 0000000..2b15bed --- /dev/null +++ b/_sources/user_guide/Reactive_Expressions.ipynb.txt @@ -0,0 +1,940 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "3ecf9ffc-96a0-4457-bc89-43cac0099e01", + "metadata": {}, + "source": [ + "## Reactive Functions & Expressions\n", + "\n", + "In the [Dependencies and Watchers](Dependencies_and_Watchers.ipynb) guide we discovered how to express dependencies and write callback functions that are invoked when parameter values change. This low-level, imperative style of expressing dynamic behavior is powerful, and works well for capturing complex behaviors in self-contained Parameterized classes with methods and Parameters. But even if you are not primarily designing a hierarchy of classes, it is still useful to be able to express dependencies between values and computations. Param 2.0 introduces a new set of declarative dynamic computation primitives that are useful even for single expressions, letting you write simple reactive functions and expressions that are re-evaluated automatically when required.\n", + "\n", + "The reactive programming model is one you might be familiar with from spreadsheets like Excel, where formulas can reference cells or ranges and dynamically (or more precisely, _reactively_) recompute when the inputs to a formula changes. In Param, Parameter objects correspond to a spreadsheet cell formula's inputs or references, and reactive expressions correspond to the formula itself. `param.bind` also allows the creation of a reactive function with arbitrary inputs.\n", + "\n", + "This user guide is structured as two main sections:\n", + "\n", + "- [Reactive Functions](#Reactive-Functions): Using `param.bind` to declare functions that react when their inputs change.\n", + "- [Reactive Expressions](#Reactive-Expressions): Using `param.rx` (or `.rx()` on Parameter objects) to wrap ordinary objects and/or parameters in a proxy that acts like the underlying object but reacts when an input changes." + ] + }, + { + "cell_type": "markdown", + "id": "c914e5f9-6c39-4dbf-b89c-d409842df3e0", + "metadata": {}, + "source": [ + "## Getting started\n", + "\n", + "Before we dive in to discover how this works behind the scenes, let's get started with a concrete example. What reactive expressions are great for is writing pipelines of operations in a natural form, i.e., without having to explicitly track and update state or the control flow. In most cases, you can simply write the same non-reactive Python code you always write, but then use arguments and option values that are reactive, so that the pipeline will re-run if the value changes.\n", + "\n", + "For an example, let's load some data into a [Pandas](https://pandas.pydata.org) DataFrame and make it reactive:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "eaa1f75f", + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import param\n", + "import param.ipython\n", + "\n", + "from param import rx" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b8bced20-02cf-4af1-83a8-47dd776a8779", + "metadata": {}, + "outputs": [], + "source": [ + "URL = 'https://datasets.holoviz.org/penguins/v1/penguins.csv'\n", + "df = rx(pd.read_csv(URL))\n", + "df.head(2)" + ] + }, + { + "cell_type": "markdown", + "id": "71463561", + "metadata": {}, + "source": [ + "Here, this is just the same code you'd normally use to make a DataFrame, apart from using `rx()` to make the DataFrame into a reactive expression. As you can see, the reactive DataFrame works like any other DataFrame, using `.head()` and any other DataFrame methods as usual. But now, let's make the fixed number `2` above into a reactive expression, and see what happens:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ac49145c", + "metadata": {}, + "outputs": [], + "source": [ + "nrows = rx(2)\n", + "df.head(nrows)" + ] + }, + { + "cell_type": "markdown", + "id": "e90e96fc", + "metadata": {}, + "source": [ + "So far, nothing's changed. But what if we change the value of `nrows`?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e9ead350", + "metadata": {}, + "outputs": [], + "source": [ + "nrows.rx.set_input(4);" + ] + }, + { + "cell_type": "markdown", + "id": "349ae1e6-d07f-4106-924f-21fbf6a4b0f7", + "metadata": {}, + "source": [ + "Whoa! As long as you are running a Jupyter notebook with a live Python process, you should have seen the dataframe \"head\" output _in_ _the_ _previous_ _cell_ update to the new value of `nrows`. That's because the reactive `df` expression in that cell captures the full pipeline of operations, automatically re-running `head` because the `nrows` has now changed. \n", + "\n", + "We've done this without having to write any special callbacks or any new functions, instead using special Python objects that capture the operations you've invoked and replay them as needed when inputs change.\n", + "\n", + "These updates should happen immediately (not only when the code cell finishes executing):" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "49b40993", + "metadata": {}, + "outputs": [], + "source": [ + "import time\n", + "\n", + "for i in range(4,9):\n", + " nrows.rx.set_input(i)\n", + " time.sleep(1)" + ] + }, + { + "cell_type": "markdown", + "id": "374de653", + "metadata": {}, + "source": [ + "You should see the previous `df.head` output react to each time `nrows` is changed, updating to reflect the current state.\n", + "\n", + "We can get more complicated if we want, with a much more complex pipeline, but still matching the same code you'd write for a non-reactive Pandas DataFrame:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "298ad9dc-7099-4e4f-bf04-d296e0433109", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "\n", + "style = rx('color: white; background-color: {color}')\n", + "color = rx('darkblue')\n", + "\n", + "def highlight_max(s, props=''):\n", + " if s.dtype.kind not in 'f':\n", + " return np.full_like(s, False)\n", + " return np.where(s == np.nanmax(s.values), props, '')\n", + "\n", + "styled_df = df.head(nrows).style.apply(highlight_max, props=style.format(color=color), axis=0)\n", + "\n", + "styled_df" + ] + }, + { + "cell_type": "markdown", + "id": "6f837bce-a2c2-4479-9adb-0a824fd29085", + "metadata": {}, + "source": [ + "Here we've made two additional reactive values (`style` and `color`), and written a Pandas pipeline that uses those values using precisely the same syntax you would with a regular Pandas expression. Since this is now a reactive Pandas expression, it will re-run whenever any of those changes. To see, try executing each of the following commands, one by one:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "16d46876-0ded-4770-bb71-fd972d8d9046", + "metadata": {}, + "outputs": [], + "source": [ + "color.rx.set_input('red');" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "aa9f36b4", + "metadata": {}, + "outputs": [], + "source": [ + "nrows.rx.set_input(nrows.rx.resolve()+2);" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b3502bc8", + "metadata": {}, + "outputs": [], + "source": [ + "color.rx.set_input('darkblue');" + ] + }, + { + "cell_type": "markdown", + "id": "8082c9db", + "metadata": {}, + "source": [ + "In the code above, we made reactive strings, numbers, and DataFrame expressions. You can also make functions reactive, which lets you make the URL reactive as well:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "106363b4", + "metadata": {}, + "outputs": [], + "source": [ + "url = rx(URL)\n", + "df = rx(pd.read_csv)(url)\n", + "df.head(2)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "30d7e585", + "metadata": {}, + "outputs": [], + "source": [ + "url.rx.set_input('https://datasets.holoviz.org/gapminders/v1/gapminders.csv');" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "742bd80f", + "metadata": {}, + "outputs": [], + "source": [ + "url.rx.set_input(URL);" + ] + }, + { + "cell_type": "markdown", + "id": "60db0a0a-a2be-4927-91a3-7cc8b10ea313", + "metadata": {}, + "source": [ + "Here, `df` is no longer wrapping up a specific DataFrame and capturing operations on it, it's wrapping up the `read_csv` call that generates the DataFrame originally, but it all still works just the same. As you can see, reactive expressions let you write code just as you usually would, but then separately control all the reactive elements of it. \n", + "\n", + "Note that we have been using Jupyter Notebook cells as a way to change these reactive values, but if you imagine using a widgets from ipywidgets or [Panel](https://panel.holoviz.org) instead, you can see how easy it is to create a reactive computation or application with user-controllable options." + ] + }, + { + "cell_type": "markdown", + "id": "57c50ba5", + "metadata": {}, + "source": [ + "## Reactive Functions\n", + "\n", + "Ok, now that you've seen reactive expressions in action, let's dive into how this all works. We'll first write a simple, non-reactive function to add two arguments:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7a4bde61", + "metadata": {}, + "outputs": [], + "source": [ + "def add(a, b):\n", + " print(f'adding {a=} and {b=}')\n", + " return a + b\n", + "\n", + "add(3, 7)" + ] + }, + { + "cell_type": "markdown", + "id": "cbfdfa4b-a04e-465b-bf1f-2910cccd870f", + "metadata": {}, + "source": [ + "Now, let's make a `Parameterized` class with some `Parameters`, here named `a` and `b`, that we'll want to add together reactively. We will also import `param.ipython` to install support for displaying \"live\" reactive components in an IPython or Jupyter notebook, re-rendering themselves when the inputs change." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f6bf6371-8dc8-4247-afaa-3ce872ed3371", + "metadata": {}, + "outputs": [], + "source": [ + "import param\n", + "import param.ipython\n", + "\n", + "class Parameters(param.Parameterized):\n", + " \n", + " a = param.Number(1)\n", + "\n", + " b = param.Number(0)\n", + "\n", + " run = param.Event()\n", + " \n", + "p = Parameters()" + ] + }, + { + "cell_type": "markdown", + "id": "1c4434e7-9b5d-4a5b-b9de-c444dae42e36", + "metadata": {}, + "source": [ + "Ok, now we can use `param.bind` to \"bind\" parameters `a` and `b` to create a reactive function:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c0a4c64e-ee64-405d-bace-605551b34234", + "metadata": {}, + "outputs": [], + "source": [ + "reactive_add = param.bind(add, p.param.a, p.param.b)\n", + "\n", + "reactive_add" + ] + }, + { + "cell_type": "markdown", + "id": "9094768c-5a39-448e-9721-e6253a2a55cb", + "metadata": {}, + "source": [ + "As you can see, `reactive_add` works just like `add`, in that it adds two arguments, but in this case it's taking the value of the `a` and `b` Parameters of `p`. Parameter `a` has been \"bound\" to the first argument and `b` to the second, and if either of them changes, the result changes. So if we change `p.a` to 5, the output above changes immediately (it \"reacts\")." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f7cd00ac-02a2-4e0c-bc98-7ce9739ed55b", + "metadata": {}, + "outputs": [], + "source": [ + "p.a += 4" + ] + }, + { + "cell_type": "markdown", + "id": "9a0e5412-b13f-42aa-bb21-4bf6f289510b", + "metadata": {}, + "source": [ + "We can also call the reactive function explicitly to return the current result as a concrete, no longer reactive value:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1e026152-1772-4437-8165-dd9788edd1fb", + "metadata": {}, + "outputs": [], + "source": [ + "reactive_add()" + ] + }, + { + "cell_type": "markdown", + "id": "16d5e9ec", + "metadata": {}, + "source": [ + "The difference between `reactive_add` and `reactive_add()` is that the first one is a function, whose display will automatically update in IPython/Jupyter thanks to the extension loaded above, while the second is a specific number (the result of calling that function a single time, never to be updated further):" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9f1c1879", + "metadata": {}, + "outputs": [], + "source": [ + "print(type(reactive_add), type(reactive_add()))" + ] + }, + { + "cell_type": "markdown", + "id": "03d62757-8b3f-4d67-b1a9-5759194408a2", + "metadata": {}, + "source": [ + "`param.bind` follows the semantics of Python's `functools.partial`, and so if you only partially bind the required arguments, you'll get a function of the remaining arguments:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "88870bf0-1d5e-42e9-9c59-b538070ad701", + "metadata": {}, + "outputs": [], + "source": [ + "add_b = param.bind(add, p.param.a)\n", + "add_b" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d516b3dc", + "metadata": {}, + "outputs": [], + "source": [ + "add_b(5)" + ] + }, + { + "cell_type": "markdown", + "id": "1b0ead79", + "metadata": {}, + "source": [ + "Note that you can bind any accepted type to make a reactive function, not just Parameters, but static values won't trigger reactive updates (here 38 will always be the same value, while the result will depend on the current value of `p.param.a`)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4badba81", + "metadata": {}, + "outputs": [], + "source": [ + "param.bind(add, p.param.a, b=38)" + ] + }, + { + "cell_type": "markdown", + "id": "5a774c07-63d7-4f40-be59-ce52242bdbd6", + "metadata": {}, + "source": [ + "## Reactive Expressions\n", + "\n", + "While reactive functions are very useful and allow writing arbitrarily complex logic, they still require writing a Python function definition, which can be verbose to write and difficult to read. With a reactive expression instead of an explicitly defined function, you can wrap any object or parameter value and apply operations on it, just as if you are working with the actual object, but now with reactive outputs. In other words, the reactive expression acts as a proxy for the underlying value, while supporting (almost) all operations that can be performed with the original object.\n", + "\n", + "### Using Parameters\n", + "\n", + "As an example, let's create reactive proxies for the `a` and `b` parameters and add them together:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "243afd62-2f10-4dd3-a264-4d9a895c3088", + "metadata": {}, + "outputs": [], + "source": [ + "q = Parameters()\n", + "\n", + "expr = q.param.a.rx() + q.param.b.rx() + 3\n", + "\n", + "expr" + ] + }, + { + "cell_type": "markdown", + "id": "f62fe083-50c9-4739-aaec-81fb31f98241", + "metadata": {}, + "source": [ + "The resulting reactive expression now reflects the result of this operation and will update automatically when one of the inputs to the operation changes, e.g. if we update parameter `a`:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f71b9341-31bb-437f-90ab-3fb5da607f0a", + "metadata": {}, + "outputs": [], + "source": [ + "q.a += 2" + ] + }, + { + "cell_type": "markdown", + "id": "a48adb7e-c340-49e1-bec1-30ca6cc2eca2", + "metadata": {}, + "source": [ + "### Resolving the expression\n", + "\n", + "Reactive objects generally just provide whatever API the underlying object has, but there are a few extra reactive-specific methods also provided. In order to avoid any clashes between the namespace of the reactive expression and the object it is wrapping, the extra methods are in a special namespace called `.rx`.\n", + "\n", + "For instance, to resolve the current value of the expression into the current value as a static (non-reactive) object, we can call `.rx.resolve()`:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4391692a-e871-4e30-a29d-1eac06a7fc74", + "metadata": {}, + "outputs": [], + "source": [ + "expr.rx.resolve()" + ] + }, + { + "cell_type": "markdown", + "id": "57d1938b", + "metadata": {}, + "source": [ + "The number displayed above is no longer tied to the reactive expression, it is its concrete output value, and so it will not update when `a` or `b` changes:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "942c52fc", + "metadata": {}, + "outputs": [], + "source": [ + "q.b += 2" + ] + }, + { + "cell_type": "markdown", + "id": "824dc59e-aea0-404e-b3c3-be134dffa8e0", + "metadata": {}, + "source": [ + "### Using literal objects as inputs\n", + "\n", + "The convenient `param.rx` function lets you make just about _anything_ reactive, without having to first define a new Parameterized object with explicit Parameters. E.g. we can create a reactive object from a static, literal value, such as a string:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9b061295-a28c-4e13-9b8c-54f9070a0a4a", + "metadata": {}, + "outputs": [], + "source": [ + "string_template = param.rx('Hello {name}!')\n", + "\n", + "string_template" + ] + }, + { + "cell_type": "markdown", + "id": "05af1fa3-bcea-4c55-809f-beb8e4049e90", + "metadata": {}, + "source": [ + "The `reactive` object now acts like a string so we can use the `.format` method to fill in the `string_template` with another reactive expression:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "56d8047b-b737-4b03-86a1-24b5b4d49bd3", + "metadata": {}, + "outputs": [], + "source": [ + "name = param.rx('world')\n", + "\n", + "str_expr = string_template.format(name=name)\n", + "\n", + "str_expr" + ] + }, + { + "cell_type": "markdown", + "id": "3218ab95-0261-4cd9-a4fe-6f552baafdb3", + "metadata": {}, + "source": [ + "### Setting the input value\n", + "\n", + "To update the input to a `rx` object we can use the `.rx.set_input(new)` method:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d4842f2f-8d17-41eb-96f0-668d0ee545d1", + "metadata": {}, + "outputs": [], + "source": [ + "name.rx.set_input('there')\n", + "\n", + "str_expr.rx.resolve()" + ] + }, + { + "cell_type": "markdown", + "id": "d1f2b719-b80e-4fca-b78e-534971eee92e", + "metadata": {}, + "source": [ + "### Functions\n", + "\n", + "In some cases you might not have a concrete value as a starting point and start with a function instead. A fully bound function can be converted to a reactive expression letting you work with the output of a function as if it was a concrete value:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6b4e1c1a-8d19-4e4f-beae-042f01d4e41a", + "metadata": {}, + "outputs": [], + "source": [ + "param.bind(add, p.param.a, p.param.b).rx() / 2" + ] + }, + { + "cell_type": "markdown", + "id": "227a230b-98b2-4097-8a6d-798ddb63b74a", + "metadata": {}, + "source": [ + "### Special Methods & Limitations\n", + "\n", + "A `reactive` proxy behaves like the underlying object it is wrapping, but only to the extent that Python allows. \n", + "Certain operations cannot be implemented in this way, e.g. Python will not allow the `len` operation to return anything but a integer and the `is` statement always checks the immediate identity of its two operands. Reactive doesn't support operator keywords (i.e. `and`, `or`, `not`, `in` and `is`), control flow keywords (i.e. `if`, `elif`, `else`), ternary conditional expressions (i.e. `a if condition else b`), and only supports iteration keywords to a limited extent (i.e. `for` or `while`). Although it does implement an iterator interface this will only work well for fixed length collections.\n", + "\n", + "#### Special methods\n", + "\n", + "Therefore `reactive` implements certain operations as special methods that exist on the `.rx` namespace alongside `rx.set` and `rx.resolve`:\n", + "\n", + "- `.rx.bool()`: Reactive version of `bool()`, casting the output value to a Boolean.\n", + "- `.rx.in_()`: Reactive version of `in`, testing if value is in the provided collection.\n", + "- `.rx.is_()`: Reactive version of `is`, testings the object identity against another object.\n", + "- `.rx.is_not()`: Reactive version of `is not`, testing the absence of object identity with another object.\n", + "- `.rx.len()`: Reactive version of `len()`, returning the length of the expression\n", + "- `.rx.pipe()`: Applies the given function (with static or reactive arguments) to this object.\n", + "- `.rx.when()`: Generates a new expression that only updates when the provided dependency updates.\n", + "- `.rx.where()`: Returns either the first or the second argument, depending on the current value of the expression." + ] + }, + { + "cell_type": "markdown", + "id": "0d1eb3de-88b0-4559-9eaf-89c74924e03d", + "metadata": {}, + "source": [ + "#### `.rx.bool()`\n", + "\n", + "Casts the current value to a Boolean True or False value:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5f45f775-facb-46f3-b06a-678f7d43d189", + "metadata": {}, + "outputs": [], + "source": [ + "rx(1).rx.bool()" + ] + }, + { + "cell_type": "markdown", + "id": "dcbf07d6-e53b-4658-86c7-15caf8eb540d", + "metadata": {}, + "source": [ + "#### `.rx.in_(arg)`\n", + "\n", + "Checks if current value is `.in_` the other collection" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "938583e7-c519-4c50-9f95-dc4099262a95", + "metadata": {}, + "outputs": [], + "source": [ + "rx(2).rx.in_([1, 2, 3])" + ] + }, + { + "cell_type": "markdown", + "id": "fb3697e6-0413-44cd-916a-dae665eb263b", + "metadata": {}, + "source": [ + "#### `.rx.is_(arg)`\n", + "\n", + "Checks the identity of the current value is the same as the argument to `.is_`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0db8bc66-bf5b-4214-b3de-063ec6d53523", + "metadata": {}, + "outputs": [], + "source": [ + "rx(None).rx.is_(None)" + ] + }, + { + "cell_type": "markdown", + "id": "819249de-513d-4286-9a6f-ed14adba70bc", + "metadata": {}, + "source": [ + "#### `.rx.is_not(arg)`\n", + "\n", + "Checks the identity of the current value is not the same as the argument to `.is_not`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "93db5be8-2023-4a67-83f0-329d0dea69d1", + "metadata": {}, + "outputs": [], + "source": [ + "rx(None).rx.is_not(None)" + ] + }, + { + "cell_type": "markdown", + "id": "9cba7f57-bc62-47bd-9cfd-b66c13d9f0e2", + "metadata": {}, + "source": [ + "#### `.rx.len()`\n", + "\n", + "Returns the length of the object" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b9552875-905a-49d8-a1a3-6a824aeb1988", + "metadata": {}, + "outputs": [], + "source": [ + "rx([1, 2, 3]).rx.len()" + ] + }, + { + "cell_type": "markdown", + "id": "2bd115e5-44bd-4d4d-b78a-a552b4072562", + "metadata": {}, + "source": [ + "#### `.rx.pipe(func, *args, **kwargs)`\n", + "\n", + "Pipes the current value into a function as the first argument, passing in additional positional and keyword arguments if provided:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c393e1e5-e18a-4b50-b355-cb3d461c8de5", + "metadata": {}, + "outputs": [], + "source": [ + "rx(1).rx.pipe(add, 2)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "34e985c6", + "metadata": {}, + "outputs": [], + "source": [ + "rx(8).rx.pipe(str)" + ] + }, + { + "cell_type": "markdown", + "id": "dfea7f35-f0fa-4bc0-954f-b01d5dcf9d6c", + "metadata": {}, + "source": [ + "#### `.rx.when(*conditions)`\n", + "\n", + "Useful when creating UIs to declare that the expression should only update when some other parameter changes, e.g. when a user clicks a button or triggers an expensive operation through some other mechanism.\n", + "\n", + "For instance, let's say we have some expensive function (here simulated using `time.sleep`). First we bind parameters `a` and `b` to this function and create a reactive expression from this function." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b0b7e3cc-4c31-4208-8f0a-efa05cc6e13e", + "metadata": {}, + "outputs": [], + "source": [ + "import time\n", + "\n", + "def expensive_function(a, b):\n", + " print(f'multiplying {a=} and {b=}')\n", + " time.sleep(2)\n", + " return a * b\n", + "\n", + "p = Parameters()\n", + "\n", + "expensive_expr = param.bind(expensive_function, p.param.a, p.param.b).rx()" + ] + }, + { + "cell_type": "markdown", + "id": "24ef7256-904b-4e74-859a-39d30d391317", + "metadata": {}, + "source": [ + "The problem we face is that if we use this `expensive_expr` whenever `a` **or** `b` are changed, then the expensive computation gets triggered *twice* if we want to change both `a` _and_ `b`. We could use `p.param.update()` to change them in bulk in this particular case, but since that's not always sufficient, here we'll gate the computation behind a third variable, e.g. the `run` `Event` parameter on the `Parameters` class." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8396d27b-81be-4185-be83-16a7bcfe0e4f", + "metadata": {}, + "outputs": [], + "source": [ + "gated_expr = expensive_expr.rx.when(p.param.run)\n", + "\n", + "gated_expr" + ] + }, + { + "cell_type": "markdown", + "id": "0b9b464b-1582-499f-b4c0-e7fe8074d8eb", + "metadata": {}, + "source": [ + "We can now safely change variables `a` and `b` separately without triggering the computation:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7f1dd442-0c57-49e2-97b5-2369adb35a7b", + "metadata": {}, + "outputs": [], + "source": [ + "p.a = 2\n", + "p.b = 4\n", + "\n", + "gated_expr.rx.resolve()" + ] + }, + { + "cell_type": "markdown", + "id": "a1443865-288a-4320-841c-586fcfea04ac", + "metadata": {}, + "source": [ + "But when we trigger the `run` parameter the expression will re-compute:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "85c2a7d1-ff76-4137-b9ce-24363177e120", + "metadata": {}, + "outputs": [], + "source": [ + "p.param.trigger('run')\n", + "\n", + "gated_expr.rx.resolve()" + ] + }, + { + "cell_type": "markdown", + "id": "d74f3645-5186-46b5-b85b-4e512cfae7bd", + "metadata": {}, + "source": [ + "#### `.rx.where(x, y)`\n", + "\n", + "Allows writing ternary conditions using the reactive paradigm. Ordinarily you can write something like this:\n", + "\n", + "```python\n", + "value_a if some_condition else value_b\n", + "``` \n", + "\n", + "to return `value_a` or `value_b` depending on some condition. However, Python does not allow overriding `if`, so `if` statements are not re-evaluated when the condition changes, and instead we have to rewrite this case using `where`.\n", + "\n", + "First we will declare a condition, which here is simply a `reactive` expression wrapping a Boolean value:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dd4f9569-b9a9-4d43-93cb-93ffba6ce927", + "metadata": {}, + "outputs": [], + "source": [ + "condition = rx(True)" + ] + }, + { + "cell_type": "markdown", + "id": "d0dff104-a095-4a97-806b-059b4c9aa622", + "metadata": {}, + "source": [ + "Now let's say we want to return either Parameter `a` or `b` depending on whether the condition is True or False. We can simply pass the values to `.where()`:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e9a36314-9a79-4e74-83e8-137f86655999", + "metadata": {}, + "outputs": [], + "source": [ + "p = Parameters(a=1, b=2)\n", + "\n", + "ternary_expr = condition.rx.where(p.param.a, p.param.b)\n", + "\n", + "ternary_expr" + ] + }, + { + "cell_type": "markdown", + "id": "88ef4e67-0fa4-45a7-8154-89f94183d3fe", + "metadata": {}, + "source": [ + "Since the initial value is `True` it returns the current value of `a`, which is `1`. However when we set the value to `False` it will return the value of `b`:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2a1ce24c-e5b3-497d-83bc-5ba351ece9ef", + "metadata": {}, + "outputs": [], + "source": [ + "condition.rx.set_input(False)\n", + "\n", + "ternary_expr.rx.resolve()" + ] + }, + { + "cell_type": "markdown", + "id": "ddb05099-e774-4f53-a345-527e44bdb5de", + "metadata": {}, + "source": [ + "Importantly, if we now change `b` the result will be reflected by the expression, reactively unless we explicitly resolve the result:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5e275e74-1d17-40bf-9382-d02a1fed61ae", + "metadata": {}, + "outputs": [], + "source": [ + "p.b = 5\n", + "\n", + "ternary_expr.rx.resolve()" + ] + }, + { + "cell_type": "markdown", + "id": "ce3ce7b3-8163-45b9-a465-17efdbca5c21", + "metadata": {}, + "source": [ + "Here the expression value depends only on `b` thanks to the `where` condition, and thus changes to `a` will no longer trigger any downstream updates until the condition is reversed again." + ] + } + ], + "metadata": { + "language_info": { + "name": "python", + "pygments_lexer": "ipython3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/_sources/user_guide/Serialization_and_Persistence.ipynb.txt b/_sources/user_guide/Serialization_and_Persistence.ipynb.txt new file mode 100644 index 0000000..80a97e3 --- /dev/null +++ b/_sources/user_guide/Serialization_and_Persistence.ipynb.txt @@ -0,0 +1,532 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "61c98db5", + "metadata": {}, + "source": [ + "# Serialization and Persistence\n", + "\n", + "Parameterized objects are declarative, explicitly defining a set of values for their parameters. This set of values constitutes the (parameter) state of the object, and this state can be saved (\"serialized\"), transmitted (if appropriate), and restored (\"deserialized\") in various ways, so that object state can be sent from one Python session to another, restored from disk, configured using a text file, and so on.\n", + "\n", + "Param offers several independent serialization mechanisms for a Parameterized object, each used for very different purposes:\n", + "- **Pickle**: creates a Python [pickle](https://docs.python.org/3/library/pickle.html) file containing not just the Parameters, but potentially any other state of the object. A pickle file is not human readable, and is not always portable between different python versions, but it is highly complete, capturing both parameter values and also non-Parameter attributes of an object. Useful for saving the entire state of a complex object and restoring it. All objects used in pickling need to be restorable, which puts some restrictions on Parameter values (e.g. requiring named functions, not lambdas).\n", + "- **JSON**: captures the state as a JSON text string. Currently and probably always limited in what can be represented, but human readable and easily exchanged with other languages. Useful for sending over a network connection, saving simple state to disk for restoring later, etc.\n", + "- **script_repr**: generates a string representation in the form of Python code that, when executed, will instantiate Parameterized objects having similar state. Useful for capturing the current state in a compact, human-readable form suitable for manual editing to create a Python file. Not all Parameters will have values representable in this way (e.g. functions defined in the current namespace will not show their function definition), but this representation is generally a reasonable human-readable starting point for hand editing. " + ] + }, + { + "cell_type": "markdown", + "id": "385b4ac1", + "metadata": {}, + "source": [ + "## Pickling Parameterized objects\n", + "\n", + "Param supports Python's native [pickle](https://docs.python.org/3/library/pickle.html) serialization format. Pickling converts a Python object into a binary stream of bytes that can be stored on disk, and unpickling converts a previously pickled byte stream into an instantiated Python object in the same or a new Python session. Pickling does not capture the actual Python source code or bytecode for functions or classes; instead, it assumes you will have the same Python source tree available for importing those definitions during unpickling and only stores the fully qualified path to those definitions. Thus pickling requires that you use named functions defined in separate importable modules rather than lambdas (unnamed functions) or other objects whose code is defined only in the main namespace or in a non-importable python script. \n", + "\n", + "Apart from such limitations, pickling is the most rich and _fully featured_ serialization option, capable of capturing the full state of an object even beyond its Parameter values. Pickling is also inherently the _least portable_ option, because it does include all the details of this internal state. The resulting .pkl files are not human readable and are not normally usable outside of Python or even across Python versions in some cases. Pickling is thus most useful for \"snapshots\" (e.g. for checkpoint-and-restore support) for a particular software installation, rather than for exporting, archiving, or configuration. See the [comparison with JSON](https://docs.python.org/3/library/pickle.html#comparison-with-json) to help understand some of the tradeoffs involved in using pickles. \n", + "\n", + "### Using pickling\n", + "\n", + "Let's look at an example of pickling and unpickling a Parameterized object:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "965dba56", + "metadata": {}, + "outputs": [], + "source": [ + "import param, pickle, time\n", + "from param.parameterized import default_label_formatter\n", + "\n", + "class A(param.Parameterized):\n", + " n = param.Number(39)\n", + " l = param.List([\"a\",\"b\"])\n", + " o = param.ClassSelector(class_=param.Parameterized)\n", + " \n", + " def __init__(self, **params):\n", + " super(A,self).__init__(**params)\n", + " self.timestamp = time.time()\n", + " \n", + "a = A(n=5, l=[1,\"e\",[2]], o=default_label_formatter.instance())\n", + "a, a.timestamp" + ] + }, + { + "cell_type": "markdown", + "id": "05c87f9b", + "metadata": {}, + "source": [ + "Here we created a Parameterized object `a` containing another Parameterized object nested in parameter `o`, with state in `self.timestamp` and not just in the Parameter values. To save this state to a file on disk, we can do a pickle \"dump\" and then delete the object so that we are sure it's no longer around:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "99e9fc90", + "metadata": {}, + "outputs": [], + "source": [ + "with open('data.pickle', 'wb') as f:\n", + " pickle.dump(a, f)\n", + " \n", + "del a" + ] + }, + { + "cell_type": "markdown", + "id": "b64088a5", + "metadata": {}, + "source": [ + "To reload the state of `a` from disk, we do a pickle \"load\":" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "806560ea", + "metadata": {}, + "outputs": [], + "source": [ + "import pickle\n", + "\n", + "with open('data.pickle', 'rb') as f:\n", + " a = pickle.load(f)\n", + " \n", + "a, a.timestamp" + ] + }, + { + "cell_type": "markdown", + "id": "39042681", + "metadata": {}, + "source": [ + "As you can see, it restored not just the Parameter values, but the timestamp (stored in the object's dictionary) as well. \n", + "\n", + "Here we are depending on the class definition of `A` actually being in memory. If we delete that definition and try to unpickle the object again, it will fail:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "67267e47", + "metadata": {}, + "outputs": [], + "source": [ + "del A\n", + "\n", + "with param.exceptions_summarized():\n", + " with open('data.pickle', 'rb') as f:\n", + " a = pickle.load(f)" + ] + }, + { + "cell_type": "markdown", + "id": "93044cbb", + "metadata": {}, + "source": [ + "Notice how the pickle has stored the fact that class `A` is defined in the main namespace, but because `__main__` is not an importable module, unpickling fails. Had `A` been defined in a module available for importing, unpickling would have succeeded here even if A had never previously been loaded.\n", + "\n", + "To use pickling in practice, you'll need to ensure that all functions and classes are named (not lambdas) and defined in some importable module, not just inline here in a notebook or script or command prompt. Even so, pickling can be very useful as a way to save and restore state of complex Parameterized objects." + ] + }, + { + "cell_type": "markdown", + "id": "3d5b6ae6", + "metadata": {}, + "source": [ + "### Pickling limitations and workarounds\n", + "\n", + "As you develop a module using Param, you'll need to pay attention to a few technical issues if you want to support pickling:\n", + "\n", + "1. **Callable parameter values**: If you provide any `param.Callable`, `param.Hooklist`, or other parameters that can accept callable objects to your users, you will need to warn them that none of those can be set to unnamed (lambda) functions or to one-off functions defined in the main namespace if they want to use pickling. Of course, you can accept such values during initial development when you may not care about pickling, but once things are working, move the one-off function to a proper importable module and then it will be safe to use as a picklable value. One way to make this work smoothly is to create `param.ParameterizedFunction` objects or other \"function object\" classes (classes whose instances are callable like functions but which may have state and are fully picklable); see e.g. the `numbergen` module for examples.\n", + "\n", + "2. **Skipping Parameters that should not be pickled**: In some cases, you may not _want_ the value of a given Parameter to be pickled and restored even while other state is being serialized. For instance, a Parameter whose value is set to a particular file path might cause errors if that path is restored when the pickle is loaded on a different system or once the file no longer exists. To cover such rare but potentially important cases, the Parameter can be defined with `pickle_default_value=False` (normally `True`), so that the instantaneous value is usable but won't be saved and restored with pickle.\n", + "\n", + "3. **Customizing settting and getting state**: You may find that your Parameter or Parameterized objects have other state that you need to handle specially, whether that's to save and restore data that isn't otherwise picklable, or to ignore state that should _not_ be pickled. For instance, if your object's dictionary contains some object that doesn't support pickling, then you can add code to omit that or to serialize it in some special way that allows it to be restored, e.g. by extracting a state dictionary fom it and then restoring it from the dictionary later. See the [pickle docs](https://docs.python.org/3/library/pickle.html#pickle-state) for the `__getstate__` and `__setstate__` methods that you can implement on your Parameter or Parameterized objects to override this behavior. Be sure to call `super(YourClass,self).__setstate__(state)` or the getstate equivalent so that you also store parameters and dictionary values as usual, if desired.\n", + "\n", + "4. **Loading old pickle files**: If you use pickles extensively, you may find yourself wanting to support pickle files generated by an older version of your own code, even though your code has since changed (with renamed modules, classes, or parameters, or options that are no longer supported, etc.). By default, unpickling will raise an exception if it finds information in your pickle file that does not match the current Python source code, but it is possible to add custom handling to translate old definitions to match current code, discard no-longer-used options, map from a previous approach into the current approach, etc. You can use `__getstate__` and `__setstate__` on your top-level object or on specific other classes to do just about anything like this, though it can get complicated to reason about. Best practice is to store the module version number or other suitable identifier as an attribute or Parameter on the top-level object to declare what version of the code was used to create the file, and you can then read this identifier later to determine whether you need to apply such conversions on reloading." + ] + }, + { + "cell_type": "markdown", + "id": "e01f6c6a", + "metadata": {}, + "source": [ + "## Serializing with JSON\n", + "\n", + "JSON is a human-readable string representation for nested dictionaries of key-value pairs. Compared to pickle, JSON is a much more limited representation, using a fixed set of types mapped to string values, and not natively supporting Python-specific types like tuples or custom Python objects. However, it is widely accepted across computer languages, and because it is human readable and editable and omits the detailed internal state of objects (unlike pickle), JSON works well as an interchange or configuration format.\n", + "\n", + "Param's JSON support is currently fairly limited, with support for serializing and deserializing individual (not nested) Parameterized objects. It is currently primarily used for synchronizing state \"across the wire\", e.g. between multiple apps running on different machines that communicate changes to shared state (e.g. for a remote GUI), but as proposed in [issue#520](https://github.com/holoviz/param/issues/520) it could be extended to be a general configuration and specification mechanism by adding conventions for specifying a Parameterized type for an object and its nested objects.\n", + "\n", + "To see how it currently works, let's start with a Parameterized object containing Parameters of different types:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "420c6148", + "metadata": {}, + "outputs": [], + "source": [ + "import param, datetime, numpy as np, pandas as pd\n", + "\n", + "ndarray = np.array([[1,2,3],[4,5,6]])\n", + "df = pd.DataFrame({'A':[1,2,3], 'B':[1.1,2.2,3.3]})\n", + "\n", + "simple_list = [1]\n", + "\n", + "class P(param.Parameterized):\n", + " a = param.Integer(default=5, doc='Int', bounds=(2,30), inclusive_bounds=(True, False))\n", + " e = param.List([1,2,3], class_=int)\n", + " g = param.Date(default=datetime.datetime.now())\n", + " l = param.Range(default=(1.1,2.3), bounds=(1,3))\n", + " m = param.String(default='baz', allow_None=True)\n", + " s = param.DataFrame(default=df, columns=(1,4), rows=(2,5))\n", + "\n", + "p = P(a=29)\n", + "p" + ] + }, + { + "cell_type": "markdown", + "id": "acebf174", + "metadata": {}, + "source": [ + "To serialize this Parameterized object to a JSON string, call `.serialize_parameters()` on it:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cf4ab02f", + "metadata": {}, + "outputs": [], + "source": [ + "s = p.param.serialize_parameters()\n", + "s" + ] + }, + { + "cell_type": "markdown", + "id": "ad0d7637", + "metadata": {}, + "source": [ + "Notice that the serialization includes not just the values set specifically on this instance (`a=29`), but also all the default values inherited from the class definition.\n", + "\n", + "You can easily select only a subset to serialize, if you wish:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "041cd4f8", + "metadata": {}, + "outputs": [], + "source": [ + "p.param.serialize_parameters(subset=['a','m'])" + ] + }, + { + "cell_type": "markdown", + "id": "d8470cef", + "metadata": {}, + "source": [ + "The JSON string can be saved to disk, sent via a network connection, stored in a database, or for any other usage suitable for a string.\n", + "\n", + "Once you are ready to deserialize the string into a Parameterized object, you'll need to know the class it came from (here `P`) and can then call its `deserialize_parameters` method to get parameter values to use in `P`'s constructor:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c2644101", + "metadata": {}, + "outputs": [], + "source": [ + "p2 = P(**P.param.deserialize_parameters(s))\n", + "p2" + ] + }, + { + "cell_type": "markdown", + "id": "d59d7765", + "metadata": {}, + "source": [ + "As you can see, we have successfully serialized our original object `p` into a new object `p2`, which could be in a different Python process on a different machine or at a different date.\n", + "\n", + "### JSON limitations and workarounds\n", + "\n", + "To see the limitations on Param's JSON support, let's look at how it works in more detail. Because the result of serialization (`s` above) is a valid JSON string, we can use the `json` library to unpack it without any knowledge of what Parameterized class it came from:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7ee520c9", + "metadata": {}, + "outputs": [], + "source": [ + "import json\n", + "dj = json.loads(s)\n", + "dj" + ] + }, + { + "cell_type": "markdown", + "id": "c2e54200", + "metadata": {}, + "source": [ + "The result is a Python dictionary of name:value pairs, some of which you can recognize as the original type (e.g. `a=29`), others that have changed type (e.g. `l=(1.1,2.3)` or `s=pd.DataFrame({'A':[1,2,3], 'B':[1.1,2.2,3.3]})`), and others that are still a string encoding of that type (e.g. `g=datetime.datetime(...)`)). If you try to pass this dictionary to your Parameterized constructor, any such value will be rejected as invalid by the corresponding Parameter:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "593c1d8b", + "metadata": {}, + "outputs": [], + "source": [ + "with param.exceptions_summarized():\n", + " P(**dj)" + ] + }, + { + "cell_type": "markdown", + "id": "216d6c7a", + "metadata": {}, + "source": [ + "That's why instead of simply `json.loads(s)`, we do `P.param.deserialize_parameters(s)`, which uses the knowledge that `P.l` is a tuple parameter to convert the resulting list `[1.1, 2.3]` into a Python tuple `(1.1, 2.3)` as required for such a parameter:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "febbc040", + "metadata": {}, + "outputs": [], + "source": [ + "print(dj['l'])\n", + "print(p2.l)" + ] + }, + { + "cell_type": "markdown", + "id": "3f410eda", + "metadata": {}, + "source": [ + "Similarly, parameters of type `param.Array` will unpack the list representation into a NumPy array, `param.DataFrame` unpacks the list of dicts of list into a Pandas DataFrame, etc. So, the encoding for your Parameterized object will always be standard JSON, but to _deserialize_ it fully into a Parameterized, you'll need to know the class it came from, or Param will not know that the list it finds was originally a tuple, dataframe, etc. \n", + "\n", + "For this reason, any Parameter that itself contains a Parameterized object will not be able to be JSON deserialized, since even if we knew what class it was (e.g. for `param.ClassSelector(class_=param.Number)`, it could be some subclass of that class. Because the class name is not currently stored in the JSON serialization, there is no way to restore it. Thus there is currently no support for JSON serializing or deserializing nested Parameterized objects.\n", + "\n", + "We do expect to add support for nested objects using something like the convention for datetime objects; see [issue#520](https://github.com/holoviz/param/issues/520)." + ] + }, + { + "cell_type": "markdown", + "id": "facde47d", + "metadata": {}, + "source": [ + "### JSON Schemas \n", + "\n", + "If you want to use your JSON representation in a separate process where Param is not available or perhaps in a different language altogether, Param can provide a [JSON schema](https://json-schema.org/) that specifies what type you are expecting for each Parameter. The schema for a given Parameterized can be obtained using the `schema` method:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "24afd3ee", + "metadata": {}, + "outputs": [], + "source": [ + "p.param.schema()" + ] + }, + { + "cell_type": "markdown", + "id": "d8d8e7bb", + "metadata": {}, + "source": [ + "Once you have the schema, you can validate that a given JSON string matches the schema, i.e. that all values included therein match the constraints listed in the schema:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0fce2ea0", + "metadata": {}, + "outputs": [], + "source": [ + "from jsonschema import validate\n", + "d = json.loads(s)\n", + "full_schema = {\"type\" : \"object\", \"properties\" : p.param.schema()}\n", + "validate(instance=d, schema=full_schema)" + ] + }, + { + "cell_type": "markdown", + "id": "4d751577", + "metadata": {}, + "source": [ + "If one of the parameter values fails to match the provided schema, you'll get an exception:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "612eaac6", + "metadata": {}, + "outputs": [], + "source": [ + "d2 = d.copy()\n", + "d2['a']='astring'\n", + "\n", + "with param.exceptions_summarized():\n", + " validate(instance=d2, schema=full_schema)" + ] + }, + { + "cell_type": "markdown", + "id": "163223d1", + "metadata": {}, + "source": [ + "The `param.schema()` call accepts the same `subset` argument as `.param.serialize_parameters()`, letting you serialize and check only a subset of the parameters if appropriate. \n", + "\n", + "You can also supply a `safe=True` argument that checks that all parameter values are _guaranteed_ to be serializable and follow the given schema. This lets you detect if there are any containers or parameters whose type is not fully specified:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9cc85749", + "metadata": {}, + "outputs": [], + "source": [ + "with param.exceptions_summarized():\n", + " full2 = {\"type\" : \"object\", \"properties\" : p.param.schema(safe=True)}\n", + " validate(instance=d, schema=full2)" + ] + }, + { + "cell_type": "markdown", + "id": "ac593fcd", + "metadata": {}, + "source": [ + "## script_repr\n", + "\n", + "Parameterized objects can be constructed through a series of interactive actions, either in a GUI or command line, or as the result of automated scripts and object-construction functions. Any parameter values can also be changed at any moment once that object has been created. If you want to capture the resulting Parameterized object with any such additions and changes, you can use the `param.script_repr()` function. `script_repr` returns a representation of that object and all nested Parameterized or other supported objects as Python code that can recreate the full object later. This approach lets you go flexibly from an interactive or indirect way of creating or modifying objects, to being able to recreate that specific object again for later use. Programs with a GUI interface can use `script_repr()` as a way of exporting a runnable version of what a user created interactively in the GUI.\n", + "\n", + "For example, let's construct a Parameterized object `p` containing Parameters whose values are themselves Parameterized objects with their own Parameters:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ad5a4d3b", + "metadata": {}, + "outputs": [], + "source": [ + "import param\n", + "\n", + "class Q(param.Parameterized):\n", + " a = param.Number(39, bounds=(0,50))\n", + " b = param.String(\"str\")\n", + "\n", + "class P(param.Parameterized):\n", + " c = param.ClassSelector(default=Q(), class_=Q)\n", + " d = param.ClassSelector(default=param.Parameterized(), class_=param.Parameterized)\n", + " e = param.Range((0,1))\n", + " \n", + "q = Q(b=\"new\")\n", + "p=P(c=q, e=(2,3))\n", + "p" + ] + }, + { + "cell_type": "markdown", + "id": "20e238cb", + "metadata": {}, + "source": [ + "We can get a script representation for this object by calling `script_repr(p)`:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e08e3d7b", + "metadata": {}, + "outputs": [], + "source": [ + "print(param.script_repr(p))" + ] + }, + { + "cell_type": "markdown", + "id": "ca0408d7", + "metadata": {}, + "source": [ + "As you can see, this representation encodes the fact that `P` was defined in the main namespace, generated inside this notebook. As you might expect, this representation has the same limitation as for `pickle` -- only classes that are in importable modules will be runnable; you'll need to save the source code to your classes in a proper Python module if you want the resulting script to be runnable. But once you have done that, you can use the `script_repr` to get a runnable version of your Parameterized object no matter how you created it, whether it was by selecting options in a GUI, adding items via a loop in a script, and so on." + ] + }, + { + "cell_type": "markdown", + "id": "ca55f9e2", + "metadata": {}, + "source": [ + "### script_repr limitations and workarounds\n", + "\n", + "Apart from making sure your functions and classes are all defined in their own importable modules, there are various considerations and limitations to keep in mind if you want to support using `script_repr`. " + ] + }, + { + "cell_type": "markdown", + "id": "75cdd8f5", + "metadata": {}, + "source": [ + "Normally, script_repr prints only parameter values that have changed from their defaults; it is designed to generate a script as close as is practical to one that a user would have typed to create the given object. If you want a record of the _complete_ set of parameter values, including all defaults, you can enable that behavior:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "57dede40", + "metadata": {}, + "outputs": [], + "source": [ + "import param.parameterized\n", + "param.parameterized.script_repr_suppress_defaults=True" + ] + }, + { + "cell_type": "markdown", + "id": "388f982f", + "metadata": {}, + "source": [ + "The resulting output is then suitable for archiving the full parameter state of that object, even if some default later gets changed in the source code. Note that Param is not able to detect all cases where a default value is unchanged, e.g. for Parameters with `instantiate=True`, which will always be treated as changed since each instance has a copy of that Parameter value independent of the original default value.\n", + "\n", + "You can control `script_repr` with keyword arguments:\n", + "\n", + "- `imports=[]`: If desired, a list of imports that can be built up over multiple script_repr calls to collect a full set of imports required for a script. Useful with `show_imports=False` except on the last script_repr call. Can be an empty list or a list containing some hard-coded imports needed.\n", + "- `prefix=\"\\n \"`: Optional prefix to use before a nested object.\n", + "- `qualify=True`: Whether the class's path will be included (e.g. \"a.b.C()\"), otherwise only the class will appear (\"C()\").\n", + "- `unknown_value=None`: determines what to do where a representation cannot be generated for something required to recreate the object. Such things include non-parameter positional and keyword arguments, and certain values of parameters (e.g. some random state objects). Supplying an `unknown_value` of `None` causes unrepresentable things to be silently ignored. If `unknown_value` is a string, that string will appear in place of any unrepresentable things. If `unknown_value` is `False`, an Exception will be raised if an unrepresentable value is encountered. \n", + "- `separator=\"\\n\"`: Separator to use between parameters.\n", + "- `show_imports=True`: Whether to include import statements in the output.\n", + "\n", + "\n", + "The `script_repr` behavior for a particular type, whether it's a Parameterized object or not, can be overridden to provide any functionality needed. Such overrides are stored in `param.parameterized.script_repr_reg`, which already contains handling for list and tuple containers, various objects with random state, functions, and modules. See examples in \n", + "`param.parameterized`." + ] + } + ], + "metadata": { + "language_info": { + "name": "python", + "pygments_lexer": "ipython3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/_sources/user_guide/Simplifying_Codebases.ipynb.txt b/_sources/user_guide/Simplifying_Codebases.ipynb.txt new file mode 100644 index 0000000..d0cedc8 --- /dev/null +++ b/_sources/user_guide/Simplifying_Codebases.ipynb.txt @@ -0,0 +1,356 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Simplifying Codebases\n", + "\n", + "Param's just a Python library, and so anything you can do with Param you can do \"manually\". So, why use Param?\n", + "\n", + "The most immediate benefit to using Param is that it allows you to greatly simplify your codebases, making them much more clear, readable, and maintainable, while simultaneously providing robust handling against error conditions.\n", + "\n", + "Param does this by letting a programmer explicitly declare the types and values of parameters accepted by the code. Param then ensures that only suitable values of those parameters ever make it through to the underlying code, removing the need to handle any of those conditions explicitly.\n", + "\n", + "To see how this works, let's create a Python class with some attributes without using Param:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "class OrdinaryClass(object):\n", + " def __init__(self, a=2, b=3, title=\"sum\"):\n", + " self.a = a\n", + " self.b = b\n", + " self.title = title\n", + " \n", + " def __call__(self):\n", + " return self.title + \": \" + str(self.a + self.b)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As this is just standard Python, we can of course instantiate this class, modify its variables, and call it:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "o1 = OrdinaryClass(b=4, title=\"Sum\")\n", + "o1.a=4\n", + "o1()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The same code written using Param would look like:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import param\n", + " \n", + "class ParamClass(param.Parameterized):\n", + " a = param.Integer(2, bounds=(0,1000), doc=\"First addend\")\n", + " b = param.Integer(3, bounds=(0,1000), doc=\"Second addend\")\n", + " title = param.String(default=\"sum\", doc=\"Title for the result\")\n", + " \n", + " def __call__(self):\n", + " return self.title + \": \" + str(self.a + self.b)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "o2 = ParamClass(b=4, title=\"Sum\")\n", + "o2()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As you can see, the Parameters here are used precisely like normal attributes once they are defined, so the code for `__call__` and for invoking the constructor are the same in both cases. It's thus generally quite straightforward to migrate an existing class into Param. So, why do that?\n", + "\n", + "Well, with fewer lines of code than the ordinary class, you've now unlocked a whole wealth of features and better behavior! For instance, what happens if a user tries to supply some inappropriate data? With Param, such errors will be caught immediately:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "with param.exceptions_summarized(): \n", + " o3 = ParamClass()\n", + " o3.b = -5" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Of course, you could always add more code to an ordinary Python class to check for errors like that, but it quickly gets unwieldy:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "class OrdinaryClass2(object):\n", + " def __init__(self, a=2, b=3, title=\"sum\"):\n", + " if type(a) is not int:\n", + " raise ValueError(\"'a' must be an integer\")\n", + " if type(b) is not int:\n", + " raise ValueError(\"'b' must be an integer\")\n", + " if a<0:\n", + " raise ValueError(\"'a' must be at least `0`\")\n", + " if b<0:\n", + " raise ValueError(\"'b' must be at least `0`\")\n", + " if type(title) is not str:\n", + " raise ValueError(\"'title' must be a string\") \n", + " \n", + " self.a = a\n", + " self.b = b\n", + " self.title = title\n", + " \n", + " def __call__(self):\n", + " return self.title + \": \" + str(self.a + self.b)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "with param.exceptions_summarized(): \n", + " OrdinaryClass2(a=\"f\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Unfortunately, catching errors in the constructor like that won't help if someone modifies the attribute directly, which won't be detected as an error:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "o4 = OrdinaryClass2()\n", + "o4.a = \"four\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Python will happily accept this incorrect value and will continue processing. It may only be much later, in a very different part of your code, that you see a mysterious error message that's then very difficult to relate back to the actual problem you need to fix:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "with param.exceptions_summarized(): \n", + " o4()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here there's no problem with the code in the cell above; `o4()` is fully valid Python; the real problem is in the preceding cell, which could have been in a completely different file or library. The error message is also obscure and confusing at this level, because the user of `o4` may have no idea why strings and integers are getting concatenated.\n", + "\n", + "To get a better error message, you _could_ move those checks into the `__call__` method, which would make sure that errors are always eventually detected:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "class OrdinaryClass3(object):\n", + " def __init__(self, a=2, b=3, title=\"sum\"): \n", + " self.a = a\n", + " self.b = b\n", + " self.title = title\n", + " \n", + " def __call__(self):\n", + " if type(self.a) is not int:\n", + " raise ValueError(\"'a' must be an integer\")\n", + " if type(self.b) is not int:\n", + " raise ValueError(\"'b' must be an integer\")\n", + " if self.a<0:\n", + " raise ValueError(\"'a' must be at least `0`\")\n", + " if self.b<0:\n", + " raise ValueError(\"'b' must be at least `0`\")\n", + " if type(self.title) is not str:\n", + " raise ValueError(\"'title' must be a string\") \n", + "\n", + " return self.title + \": \" + str(self.a + self.b)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "o5 = OrdinaryClass3()\n", + "o5.a = \"four\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "with param.exceptions_summarized(): \n", + " o5()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "But you'd now have to check for errors in _every_ _single_ _method_ that might use those parameters. Worse, you still only detect the problem very late, far from where it was first introduced. Any distance between the error and the error report makes it much more difficult to address, as the user then has to track down where in the code `a` might have gotten set to a non-integer.\n", + "\n", + "With Param you can catch such problems at their start, as soon as an incorrect value is provided, when it is still simple to detect and correct it. To get those same features in hand-written Python code, you would need to provide explicit getters and setters, which is made easier with Python properties and decorators, but is still quite unwieldy:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "class OrdinaryClass4(object):\n", + " def __init__(self, a=2, b=3, title=\"sum\"):\n", + " self.a = a\n", + " self.b = b\n", + " self.title = title\n", + " \n", + " @property\n", + " def a(self): return self.__a\n", + " @a.setter\n", + " def a(self, a):\n", + " if type(a) is not int:\n", + " raise ValueError(\"'a' must be an integer\")\n", + " if a < 0:\n", + " raise ValueError(\"'a' must be at least `0`\")\n", + " self.__a = a\n", + " \n", + " @property\n", + " def b(self): return self.__b\n", + " @b.setter\n", + " def b(self, b):\n", + " if type(b) is not int:\n", + " raise ValueError(\"'a' must be an integer\")\n", + " if b < 0:\n", + " raise ValueError(\"'a' must be at least `0`\")\n", + " self.__b = b\n", + "\n", + " @property\n", + " def title(self): return self.__title\n", + " def title(self, b):\n", + " if type(title) is not string:\n", + " raise ValueError(\"'title' must be a string\")\n", + " self.__title = title\n", + "\n", + " def __call__(self):\n", + " return self.title + \": \" + str(self.a + self.b)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "o5=OrdinaryClass4()\n", + "o5()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "with param.exceptions_summarized(): \n", + " o5=OrdinaryClass4()\n", + " o5.b=-6" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note that this code has an easily overlooked mistake in it, reporting `a` rather than `b` as the problem. This sort of error is extremely common in copy-pasted validation code of this type, because tests rarely exercise all of the error conditions involved.\n", + "\n", + "As you can see, even getting close to the automatic validation already provided by Param requires 8 methods and >30 highly repetitive lines of code, even when using relatively esoteric Python features like properties and decorators, and still doesn't yet implement other Param features like automatic documentation, attribute inheritance, or dynamic values. With Param, the corresponding `ParamClass` code only requires 6 lines and no fancy techniques beyond Python classes. Most importantly, the Param version lets readers and program authors focus directly on what this code actually does, which is to compute a function from three provided parameters:\n", + "\n", + "```\n", + "class ParamClass(param.Parameterized):\n", + " a = param.Integer(2, bounds=(0,1000), doc=\"First addend\")\n", + " b = param.Integer(3, bounds=(0,1000), doc=\"Second addend\")\n", + " title = param.String(default=\"sum\", doc=\"Title for the result\")\n", + " \n", + " def __call__(self):\n", + " return self.title + \": \" + str(self.a + self.b)\n", + "```\n", + "\n", + "Even a quick skim of this code reveals what parameters are available, what values they will accept, what the default values are, and how those parameters will be used in the method. Plus the actual code of the method stands out immediately, as all the code is either parameters or actual functionality. In contrast, users of OrdinaryClass3 will have to read through dozens of lines of code to discern even basic information about usage, or else authors of the code will need to create and maintain docstrings that may or may not match the actual code over time and will further increase the amount of text to write and maintain." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Programming contracts\n", + "\n", + "If you think about the examples above, you can see how Param makes it simple for programmers to make a contract with their users, being explicit and clear what will be accepted and rejected, while also allowing programmers to make safe assumptions about what inputs the code may ever receive. There is no need for `__call__` _ever_ to check for the type of one of its parameters, whether it's in the range allowed, or any other property that can be enforced by Param. Your custom code can then be much more linear and straightforward, getting right to work with the actual task at hand, without having to have reams of `if` statements and `asserts()` that disrupt the flow of the source file and make the reader get sidetracked in error-handling code. Param lets you once and for all declare what this code accepts, which is both clear documentation to the user and a guarantee that the programmer can forget about any other possible value a user might someday supply.\n", + "\n", + "Crucially, these contracts apply not just between the user and a given piece of code, but also between components of the system itself. When validation code is expensive, as in ordinary Python, programmers will typically do it only at the edges of the system, where input from the user is accepted. But expressing types and ranges is so easy in Param, it can be done for any major component in the system. The Parameter list declares very clearly what that component accepts, which lets the code for that component ignore all potential inputs that are disallowed by the Parameter specifications, while correctly advertising to the rest of the codebase what inputs are allowed. Programmers can thus focus on their particular components of interest, knowing precisely what inputs will ever be let through, without having to reason about the flow of configuration and data throughout the whole system.\n", + "\n", + "Without Param, you should expect Python code to be full of confusing error checking and handling of different input types, while still only catching a small fraction of the possible incorrect inputs that could be provided. But Param-based code should be dramatically easier to read, easier to maintain, easier to develop, and nearly bulletproof against mistaken or even malicious usage. " + ] + } + ], + "metadata": { + "language_info": { + "name": "python", + "pygments_lexer": "ipython3" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/_sources/user_guide/index.md.txt b/_sources/user_guide/index.md.txt new file mode 100644 index 0000000..a2bba2d --- /dev/null +++ b/_sources/user_guide/index.md.txt @@ -0,0 +1,35 @@ +# User Guide + +This user guide provides detailed information about how to use Param, assuming you have worked through the Getting Started guide. + +- [Simplifying Codebases](./Simplifying_Codebases): How Param allows you to eliminate boilerplate and unsafe code +- [Parameters](./Parameters): Using parameters (Class vs. instance parameters, setting defaults, etc.) +- [Parameter Types](./Parameter_Types): Predefined Parameter classes available for your use +- [Dependencies and Watchers](./Dependencies_and_Watchers): Expressing relationships between parameters and parameters or code, and triggering events +- [Reactive Expressions](./Reactive_Expressions): How to write expressions and functions that automatically re-evaluate when their parameter inputs change. +- [Serialization and Persistence](./Serialization_and_Persistence): Saving the state of a Parameterized object to a text, script, or pickle file +- [Outputs](./Outputs): Output types and connecting output to Parameter inputs +- [Logging and Warnings](./Logging_and_Warnings): Logging, messaging, warning, and raising errors on Parameterized objects +- [ParameterizedFunctions](./ParameterizedFunctions): Parameterized function objects, for configurable callables +- [Dynamic Parameters](./Dynamic_Parameters): Using dynamic parameter values with and without Numbergen +- [How Param Works](./How_Param_Works): Internal details, for Param developers and power users +- [Using Param in GUIs](https://panel.holoviz.org/how_to/param/index.html): (external site) Using Param with Panel to make GUIs + +```{toctree} +--- +hidden: true +maxdepth: 2 +--- +Overview +Simplifying Codebases +Parameters +Parameter Types +Dependencies and Watchers +Reactive Expressions +Serialization and Persistence +Outputs +Logging and Warnings +ParameterizedFunctions +Dynamic Parameters +How Param Works +``` diff --git a/_sphinx_design_static/design-style.1e8bd061cd6da7fc9cf755528e8ffc24.min.css b/_sphinx_design_static/design-style.1e8bd061cd6da7fc9cf755528e8ffc24.min.css new file mode 100644 index 0000000..eb19f69 --- /dev/null +++ b/_sphinx_design_static/design-style.1e8bd061cd6da7fc9cf755528e8ffc24.min.css @@ -0,0 +1 @@ +.sd-bg-primary{background-color:var(--sd-color-primary) !important}.sd-bg-text-primary{color:var(--sd-color-primary-text) !important}button.sd-bg-primary:focus,button.sd-bg-primary:hover{background-color:var(--sd-color-primary-highlight) !important}a.sd-bg-primary:focus,a.sd-bg-primary:hover{background-color:var(--sd-color-primary-highlight) !important}.sd-bg-secondary{background-color:var(--sd-color-secondary) !important}.sd-bg-text-secondary{color:var(--sd-color-secondary-text) !important}button.sd-bg-secondary:focus,button.sd-bg-secondary:hover{background-color:var(--sd-color-secondary-highlight) !important}a.sd-bg-secondary:focus,a.sd-bg-secondary:hover{background-color:var(--sd-color-secondary-highlight) !important}.sd-bg-success{background-color:var(--sd-color-success) !important}.sd-bg-text-success{color:var(--sd-color-success-text) !important}button.sd-bg-success:focus,button.sd-bg-success:hover{background-color:var(--sd-color-success-highlight) !important}a.sd-bg-success:focus,a.sd-bg-success:hover{background-color:var(--sd-color-success-highlight) !important}.sd-bg-info{background-color:var(--sd-color-info) !important}.sd-bg-text-info{color:var(--sd-color-info-text) !important}button.sd-bg-info:focus,button.sd-bg-info:hover{background-color:var(--sd-color-info-highlight) !important}a.sd-bg-info:focus,a.sd-bg-info:hover{background-color:var(--sd-color-info-highlight) !important}.sd-bg-warning{background-color:var(--sd-color-warning) !important}.sd-bg-text-warning{color:var(--sd-color-warning-text) !important}button.sd-bg-warning:focus,button.sd-bg-warning:hover{background-color:var(--sd-color-warning-highlight) !important}a.sd-bg-warning:focus,a.sd-bg-warning:hover{background-color:var(--sd-color-warning-highlight) !important}.sd-bg-danger{background-color:var(--sd-color-danger) !important}.sd-bg-text-danger{color:var(--sd-color-danger-text) !important}button.sd-bg-danger:focus,button.sd-bg-danger:hover{background-color:var(--sd-color-danger-highlight) !important}a.sd-bg-danger:focus,a.sd-bg-danger:hover{background-color:var(--sd-color-danger-highlight) !important}.sd-bg-light{background-color:var(--sd-color-light) !important}.sd-bg-text-light{color:var(--sd-color-light-text) !important}button.sd-bg-light:focus,button.sd-bg-light:hover{background-color:var(--sd-color-light-highlight) !important}a.sd-bg-light:focus,a.sd-bg-light:hover{background-color:var(--sd-color-light-highlight) !important}.sd-bg-muted{background-color:var(--sd-color-muted) !important}.sd-bg-text-muted{color:var(--sd-color-muted-text) !important}button.sd-bg-muted:focus,button.sd-bg-muted:hover{background-color:var(--sd-color-muted-highlight) !important}a.sd-bg-muted:focus,a.sd-bg-muted:hover{background-color:var(--sd-color-muted-highlight) !important}.sd-bg-dark{background-color:var(--sd-color-dark) !important}.sd-bg-text-dark{color:var(--sd-color-dark-text) !important}button.sd-bg-dark:focus,button.sd-bg-dark:hover{background-color:var(--sd-color-dark-highlight) !important}a.sd-bg-dark:focus,a.sd-bg-dark:hover{background-color:var(--sd-color-dark-highlight) !important}.sd-bg-black{background-color:var(--sd-color-black) !important}.sd-bg-text-black{color:var(--sd-color-black-text) !important}button.sd-bg-black:focus,button.sd-bg-black:hover{background-color:var(--sd-color-black-highlight) !important}a.sd-bg-black:focus,a.sd-bg-black:hover{background-color:var(--sd-color-black-highlight) !important}.sd-bg-white{background-color:var(--sd-color-white) !important}.sd-bg-text-white{color:var(--sd-color-white-text) !important}button.sd-bg-white:focus,button.sd-bg-white:hover{background-color:var(--sd-color-white-highlight) !important}a.sd-bg-white:focus,a.sd-bg-white:hover{background-color:var(--sd-color-white-highlight) !important}.sd-text-primary,.sd-text-primary>p{color:var(--sd-color-primary) !important}a.sd-text-primary:focus,a.sd-text-primary:hover{color:var(--sd-color-primary-highlight) !important}.sd-text-secondary,.sd-text-secondary>p{color:var(--sd-color-secondary) !important}a.sd-text-secondary:focus,a.sd-text-secondary:hover{color:var(--sd-color-secondary-highlight) !important}.sd-text-success,.sd-text-success>p{color:var(--sd-color-success) !important}a.sd-text-success:focus,a.sd-text-success:hover{color:var(--sd-color-success-highlight) !important}.sd-text-info,.sd-text-info>p{color:var(--sd-color-info) !important}a.sd-text-info:focus,a.sd-text-info:hover{color:var(--sd-color-info-highlight) !important}.sd-text-warning,.sd-text-warning>p{color:var(--sd-color-warning) !important}a.sd-text-warning:focus,a.sd-text-warning:hover{color:var(--sd-color-warning-highlight) !important}.sd-text-danger,.sd-text-danger>p{color:var(--sd-color-danger) !important}a.sd-text-danger:focus,a.sd-text-danger:hover{color:var(--sd-color-danger-highlight) !important}.sd-text-light,.sd-text-light>p{color:var(--sd-color-light) !important}a.sd-text-light:focus,a.sd-text-light:hover{color:var(--sd-color-light-highlight) !important}.sd-text-muted,.sd-text-muted>p{color:var(--sd-color-muted) !important}a.sd-text-muted:focus,a.sd-text-muted:hover{color:var(--sd-color-muted-highlight) !important}.sd-text-dark,.sd-text-dark>p{color:var(--sd-color-dark) !important}a.sd-text-dark:focus,a.sd-text-dark:hover{color:var(--sd-color-dark-highlight) !important}.sd-text-black,.sd-text-black>p{color:var(--sd-color-black) !important}a.sd-text-black:focus,a.sd-text-black:hover{color:var(--sd-color-black-highlight) !important}.sd-text-white,.sd-text-white>p{color:var(--sd-color-white) !important}a.sd-text-white:focus,a.sd-text-white:hover{color:var(--sd-color-white-highlight) !important}.sd-outline-primary{border-color:var(--sd-color-primary) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-primary:focus,a.sd-outline-primary:hover{border-color:var(--sd-color-primary-highlight) !important}.sd-outline-secondary{border-color:var(--sd-color-secondary) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-secondary:focus,a.sd-outline-secondary:hover{border-color:var(--sd-color-secondary-highlight) !important}.sd-outline-success{border-color:var(--sd-color-success) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-success:focus,a.sd-outline-success:hover{border-color:var(--sd-color-success-highlight) !important}.sd-outline-info{border-color:var(--sd-color-info) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-info:focus,a.sd-outline-info:hover{border-color:var(--sd-color-info-highlight) !important}.sd-outline-warning{border-color:var(--sd-color-warning) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-warning:focus,a.sd-outline-warning:hover{border-color:var(--sd-color-warning-highlight) !important}.sd-outline-danger{border-color:var(--sd-color-danger) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-danger:focus,a.sd-outline-danger:hover{border-color:var(--sd-color-danger-highlight) !important}.sd-outline-light{border-color:var(--sd-color-light) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-light:focus,a.sd-outline-light:hover{border-color:var(--sd-color-light-highlight) !important}.sd-outline-muted{border-color:var(--sd-color-muted) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-muted:focus,a.sd-outline-muted:hover{border-color:var(--sd-color-muted-highlight) !important}.sd-outline-dark{border-color:var(--sd-color-dark) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-dark:focus,a.sd-outline-dark:hover{border-color:var(--sd-color-dark-highlight) !important}.sd-outline-black{border-color:var(--sd-color-black) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-black:focus,a.sd-outline-black:hover{border-color:var(--sd-color-black-highlight) !important}.sd-outline-white{border-color:var(--sd-color-white) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-white:focus,a.sd-outline-white:hover{border-color:var(--sd-color-white-highlight) !important}.sd-bg-transparent{background-color:transparent !important}.sd-outline-transparent{border-color:transparent !important}.sd-text-transparent{color:transparent !important}.sd-p-0{padding:0 !important}.sd-pt-0,.sd-py-0{padding-top:0 !important}.sd-pr-0,.sd-px-0{padding-right:0 !important}.sd-pb-0,.sd-py-0{padding-bottom:0 !important}.sd-pl-0,.sd-px-0{padding-left:0 !important}.sd-p-1{padding:.25rem !important}.sd-pt-1,.sd-py-1{padding-top:.25rem !important}.sd-pr-1,.sd-px-1{padding-right:.25rem !important}.sd-pb-1,.sd-py-1{padding-bottom:.25rem !important}.sd-pl-1,.sd-px-1{padding-left:.25rem !important}.sd-p-2{padding:.5rem !important}.sd-pt-2,.sd-py-2{padding-top:.5rem !important}.sd-pr-2,.sd-px-2{padding-right:.5rem !important}.sd-pb-2,.sd-py-2{padding-bottom:.5rem !important}.sd-pl-2,.sd-px-2{padding-left:.5rem !important}.sd-p-3{padding:1rem !important}.sd-pt-3,.sd-py-3{padding-top:1rem !important}.sd-pr-3,.sd-px-3{padding-right:1rem !important}.sd-pb-3,.sd-py-3{padding-bottom:1rem !important}.sd-pl-3,.sd-px-3{padding-left:1rem !important}.sd-p-4{padding:1.5rem !important}.sd-pt-4,.sd-py-4{padding-top:1.5rem !important}.sd-pr-4,.sd-px-4{padding-right:1.5rem !important}.sd-pb-4,.sd-py-4{padding-bottom:1.5rem !important}.sd-pl-4,.sd-px-4{padding-left:1.5rem !important}.sd-p-5{padding:3rem !important}.sd-pt-5,.sd-py-5{padding-top:3rem !important}.sd-pr-5,.sd-px-5{padding-right:3rem !important}.sd-pb-5,.sd-py-5{padding-bottom:3rem !important}.sd-pl-5,.sd-px-5{padding-left:3rem !important}.sd-m-auto{margin:auto !important}.sd-mt-auto,.sd-my-auto{margin-top:auto !important}.sd-mr-auto,.sd-mx-auto{margin-right:auto !important}.sd-mb-auto,.sd-my-auto{margin-bottom:auto !important}.sd-ml-auto,.sd-mx-auto{margin-left:auto !important}.sd-m-0{margin:0 !important}.sd-mt-0,.sd-my-0{margin-top:0 !important}.sd-mr-0,.sd-mx-0{margin-right:0 !important}.sd-mb-0,.sd-my-0{margin-bottom:0 !important}.sd-ml-0,.sd-mx-0{margin-left:0 !important}.sd-m-1{margin:.25rem !important}.sd-mt-1,.sd-my-1{margin-top:.25rem !important}.sd-mr-1,.sd-mx-1{margin-right:.25rem !important}.sd-mb-1,.sd-my-1{margin-bottom:.25rem !important}.sd-ml-1,.sd-mx-1{margin-left:.25rem !important}.sd-m-2{margin:.5rem !important}.sd-mt-2,.sd-my-2{margin-top:.5rem !important}.sd-mr-2,.sd-mx-2{margin-right:.5rem !important}.sd-mb-2,.sd-my-2{margin-bottom:.5rem !important}.sd-ml-2,.sd-mx-2{margin-left:.5rem !important}.sd-m-3{margin:1rem !important}.sd-mt-3,.sd-my-3{margin-top:1rem !important}.sd-mr-3,.sd-mx-3{margin-right:1rem !important}.sd-mb-3,.sd-my-3{margin-bottom:1rem !important}.sd-ml-3,.sd-mx-3{margin-left:1rem !important}.sd-m-4{margin:1.5rem !important}.sd-mt-4,.sd-my-4{margin-top:1.5rem !important}.sd-mr-4,.sd-mx-4{margin-right:1.5rem !important}.sd-mb-4,.sd-my-4{margin-bottom:1.5rem !important}.sd-ml-4,.sd-mx-4{margin-left:1.5rem !important}.sd-m-5{margin:3rem !important}.sd-mt-5,.sd-my-5{margin-top:3rem !important}.sd-mr-5,.sd-mx-5{margin-right:3rem !important}.sd-mb-5,.sd-my-5{margin-bottom:3rem !important}.sd-ml-5,.sd-mx-5{margin-left:3rem !important}.sd-w-25{width:25% !important}.sd-w-50{width:50% !important}.sd-w-75{width:75% !important}.sd-w-100{width:100% !important}.sd-w-auto{width:auto !important}.sd-h-25{height:25% !important}.sd-h-50{height:50% !important}.sd-h-75{height:75% !important}.sd-h-100{height:100% !important}.sd-h-auto{height:auto !important}.sd-d-none{display:none !important}.sd-d-inline{display:inline !important}.sd-d-inline-block{display:inline-block !important}.sd-d-block{display:block !important}.sd-d-grid{display:grid !important}.sd-d-flex-row{display:-ms-flexbox !important;display:flex !important;flex-direction:row !important}.sd-d-flex-column{display:-ms-flexbox !important;display:flex !important;flex-direction:column !important}.sd-d-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}@media(min-width: 576px){.sd-d-sm-none{display:none !important}.sd-d-sm-inline{display:inline !important}.sd-d-sm-inline-block{display:inline-block !important}.sd-d-sm-block{display:block !important}.sd-d-sm-grid{display:grid !important}.sd-d-sm-flex{display:-ms-flexbox !important;display:flex !important}.sd-d-sm-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}}@media(min-width: 768px){.sd-d-md-none{display:none !important}.sd-d-md-inline{display:inline !important}.sd-d-md-inline-block{display:inline-block !important}.sd-d-md-block{display:block !important}.sd-d-md-grid{display:grid !important}.sd-d-md-flex{display:-ms-flexbox !important;display:flex !important}.sd-d-md-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}}@media(min-width: 992px){.sd-d-lg-none{display:none !important}.sd-d-lg-inline{display:inline !important}.sd-d-lg-inline-block{display:inline-block !important}.sd-d-lg-block{display:block !important}.sd-d-lg-grid{display:grid !important}.sd-d-lg-flex{display:-ms-flexbox !important;display:flex !important}.sd-d-lg-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}}@media(min-width: 1200px){.sd-d-xl-none{display:none !important}.sd-d-xl-inline{display:inline !important}.sd-d-xl-inline-block{display:inline-block !important}.sd-d-xl-block{display:block !important}.sd-d-xl-grid{display:grid !important}.sd-d-xl-flex{display:-ms-flexbox !important;display:flex !important}.sd-d-xl-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}}.sd-align-major-start{justify-content:flex-start !important}.sd-align-major-end{justify-content:flex-end !important}.sd-align-major-center{justify-content:center !important}.sd-align-major-justify{justify-content:space-between !important}.sd-align-major-spaced{justify-content:space-evenly !important}.sd-align-minor-start{align-items:flex-start !important}.sd-align-minor-end{align-items:flex-end !important}.sd-align-minor-center{align-items:center !important}.sd-align-minor-stretch{align-items:stretch !important}.sd-text-justify{text-align:justify !important}.sd-text-left{text-align:left !important}.sd-text-right{text-align:right !important}.sd-text-center{text-align:center !important}.sd-font-weight-light{font-weight:300 !important}.sd-font-weight-lighter{font-weight:lighter !important}.sd-font-weight-normal{font-weight:400 !important}.sd-font-weight-bold{font-weight:700 !important}.sd-font-weight-bolder{font-weight:bolder !important}.sd-font-italic{font-style:italic !important}.sd-text-decoration-none{text-decoration:none !important}.sd-text-lowercase{text-transform:lowercase !important}.sd-text-uppercase{text-transform:uppercase !important}.sd-text-capitalize{text-transform:capitalize !important}.sd-text-wrap{white-space:normal !important}.sd-text-nowrap{white-space:nowrap !important}.sd-text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sd-fs-1,.sd-fs-1>p{font-size:calc(1.375rem + 1.5vw) !important;line-height:unset !important}.sd-fs-2,.sd-fs-2>p{font-size:calc(1.325rem + 0.9vw) !important;line-height:unset !important}.sd-fs-3,.sd-fs-3>p{font-size:calc(1.3rem + 0.6vw) !important;line-height:unset !important}.sd-fs-4,.sd-fs-4>p{font-size:calc(1.275rem + 0.3vw) !important;line-height:unset !important}.sd-fs-5,.sd-fs-5>p{font-size:1.25rem !important;line-height:unset !important}.sd-fs-6,.sd-fs-6>p{font-size:1rem !important;line-height:unset !important}.sd-border-0{border:0 solid !important}.sd-border-top-0{border-top:0 solid !important}.sd-border-bottom-0{border-bottom:0 solid !important}.sd-border-right-0{border-right:0 solid !important}.sd-border-left-0{border-left:0 solid !important}.sd-border-1{border:1px solid !important}.sd-border-top-1{border-top:1px solid !important}.sd-border-bottom-1{border-bottom:1px solid !important}.sd-border-right-1{border-right:1px solid !important}.sd-border-left-1{border-left:1px solid !important}.sd-border-2{border:2px solid !important}.sd-border-top-2{border-top:2px solid !important}.sd-border-bottom-2{border-bottom:2px solid !important}.sd-border-right-2{border-right:2px solid !important}.sd-border-left-2{border-left:2px solid !important}.sd-border-3{border:3px solid !important}.sd-border-top-3{border-top:3px solid !important}.sd-border-bottom-3{border-bottom:3px solid !important}.sd-border-right-3{border-right:3px solid !important}.sd-border-left-3{border-left:3px solid !important}.sd-border-4{border:4px solid !important}.sd-border-top-4{border-top:4px solid !important}.sd-border-bottom-4{border-bottom:4px solid !important}.sd-border-right-4{border-right:4px solid !important}.sd-border-left-4{border-left:4px solid !important}.sd-border-5{border:5px solid !important}.sd-border-top-5{border-top:5px solid !important}.sd-border-bottom-5{border-bottom:5px solid !important}.sd-border-right-5{border-right:5px solid !important}.sd-border-left-5{border-left:5px solid !important}.sd-rounded-0{border-radius:0 !important}.sd-rounded-1{border-radius:.2rem !important}.sd-rounded-2{border-radius:.3rem !important}.sd-rounded-3{border-radius:.5rem !important}.sd-rounded-pill{border-radius:50rem !important}.sd-rounded-circle{border-radius:50% !important}.shadow-none{box-shadow:none !important}.sd-shadow-sm{box-shadow:0 .125rem .25rem var(--sd-color-shadow) !important}.sd-shadow-md{box-shadow:0 .5rem 1rem var(--sd-color-shadow) !important}.sd-shadow-lg{box-shadow:0 1rem 3rem var(--sd-color-shadow) !important}@keyframes sd-slide-from-left{0%{transform:translateX(-100%)}100%{transform:translateX(0)}}@keyframes sd-slide-from-right{0%{transform:translateX(200%)}100%{transform:translateX(0)}}@keyframes sd-grow100{0%{transform:scale(0);opacity:.5}100%{transform:scale(1);opacity:1}}@keyframes sd-grow50{0%{transform:scale(0.5);opacity:.5}100%{transform:scale(1);opacity:1}}@keyframes sd-grow50-rot20{0%{transform:scale(0.5) rotateZ(-20deg);opacity:.5}75%{transform:scale(1) rotateZ(5deg);opacity:1}95%{transform:scale(1) rotateZ(-1deg);opacity:1}100%{transform:scale(1) rotateZ(0);opacity:1}}.sd-animate-slide-from-left{animation:1s ease-out 0s 1 normal none running sd-slide-from-left}.sd-animate-slide-from-right{animation:1s ease-out 0s 1 normal none running sd-slide-from-right}.sd-animate-grow100{animation:1s ease-out 0s 1 normal none running sd-grow100}.sd-animate-grow50{animation:1s ease-out 0s 1 normal none running sd-grow50}.sd-animate-grow50-rot20{animation:1s ease-out 0s 1 normal none running sd-grow50-rot20}.sd-badge{display:inline-block;padding:.35em .65em;font-size:.75em;font-weight:700;line-height:1;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25rem}.sd-badge:empty{display:none}a.sd-badge{text-decoration:none}.sd-btn .sd-badge{position:relative;top:-1px}.sd-btn{background-color:transparent;border:1px solid transparent;border-radius:.25rem;cursor:pointer;display:inline-block;font-weight:400;font-size:1rem;line-height:1.5;padding:.375rem .75rem;text-align:center;text-decoration:none;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;vertical-align:middle;user-select:none;-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none}.sd-btn:hover{text-decoration:none}@media(prefers-reduced-motion: reduce){.sd-btn{transition:none}}.sd-btn-primary,.sd-btn-outline-primary:hover,.sd-btn-outline-primary:focus{color:var(--sd-color-primary-text) !important;background-color:var(--sd-color-primary) !important;border-color:var(--sd-color-primary) !important;border-width:1px !important;border-style:solid !important}.sd-btn-primary:hover,.sd-btn-primary:focus{color:var(--sd-color-primary-text) !important;background-color:var(--sd-color-primary-highlight) !important;border-color:var(--sd-color-primary-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-primary{color:var(--sd-color-primary) !important;border-color:var(--sd-color-primary) !important;border-width:1px !important;border-style:solid !important}.sd-btn-secondary,.sd-btn-outline-secondary:hover,.sd-btn-outline-secondary:focus{color:var(--sd-color-secondary-text) !important;background-color:var(--sd-color-secondary) !important;border-color:var(--sd-color-secondary) !important;border-width:1px !important;border-style:solid !important}.sd-btn-secondary:hover,.sd-btn-secondary:focus{color:var(--sd-color-secondary-text) !important;background-color:var(--sd-color-secondary-highlight) !important;border-color:var(--sd-color-secondary-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-secondary{color:var(--sd-color-secondary) !important;border-color:var(--sd-color-secondary) !important;border-width:1px !important;border-style:solid !important}.sd-btn-success,.sd-btn-outline-success:hover,.sd-btn-outline-success:focus{color:var(--sd-color-success-text) !important;background-color:var(--sd-color-success) !important;border-color:var(--sd-color-success) !important;border-width:1px !important;border-style:solid !important}.sd-btn-success:hover,.sd-btn-success:focus{color:var(--sd-color-success-text) !important;background-color:var(--sd-color-success-highlight) !important;border-color:var(--sd-color-success-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-success{color:var(--sd-color-success) !important;border-color:var(--sd-color-success) !important;border-width:1px !important;border-style:solid !important}.sd-btn-info,.sd-btn-outline-info:hover,.sd-btn-outline-info:focus{color:var(--sd-color-info-text) !important;background-color:var(--sd-color-info) !important;border-color:var(--sd-color-info) !important;border-width:1px !important;border-style:solid !important}.sd-btn-info:hover,.sd-btn-info:focus{color:var(--sd-color-info-text) !important;background-color:var(--sd-color-info-highlight) !important;border-color:var(--sd-color-info-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-info{color:var(--sd-color-info) !important;border-color:var(--sd-color-info) !important;border-width:1px !important;border-style:solid !important}.sd-btn-warning,.sd-btn-outline-warning:hover,.sd-btn-outline-warning:focus{color:var(--sd-color-warning-text) !important;background-color:var(--sd-color-warning) !important;border-color:var(--sd-color-warning) !important;border-width:1px !important;border-style:solid !important}.sd-btn-warning:hover,.sd-btn-warning:focus{color:var(--sd-color-warning-text) !important;background-color:var(--sd-color-warning-highlight) !important;border-color:var(--sd-color-warning-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-warning{color:var(--sd-color-warning) !important;border-color:var(--sd-color-warning) !important;border-width:1px !important;border-style:solid !important}.sd-btn-danger,.sd-btn-outline-danger:hover,.sd-btn-outline-danger:focus{color:var(--sd-color-danger-text) !important;background-color:var(--sd-color-danger) !important;border-color:var(--sd-color-danger) !important;border-width:1px !important;border-style:solid !important}.sd-btn-danger:hover,.sd-btn-danger:focus{color:var(--sd-color-danger-text) !important;background-color:var(--sd-color-danger-highlight) !important;border-color:var(--sd-color-danger-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-danger{color:var(--sd-color-danger) !important;border-color:var(--sd-color-danger) !important;border-width:1px !important;border-style:solid !important}.sd-btn-light,.sd-btn-outline-light:hover,.sd-btn-outline-light:focus{color:var(--sd-color-light-text) !important;background-color:var(--sd-color-light) !important;border-color:var(--sd-color-light) !important;border-width:1px !important;border-style:solid !important}.sd-btn-light:hover,.sd-btn-light:focus{color:var(--sd-color-light-text) !important;background-color:var(--sd-color-light-highlight) !important;border-color:var(--sd-color-light-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-light{color:var(--sd-color-light) !important;border-color:var(--sd-color-light) !important;border-width:1px !important;border-style:solid !important}.sd-btn-muted,.sd-btn-outline-muted:hover,.sd-btn-outline-muted:focus{color:var(--sd-color-muted-text) !important;background-color:var(--sd-color-muted) !important;border-color:var(--sd-color-muted) !important;border-width:1px !important;border-style:solid !important}.sd-btn-muted:hover,.sd-btn-muted:focus{color:var(--sd-color-muted-text) !important;background-color:var(--sd-color-muted-highlight) !important;border-color:var(--sd-color-muted-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-muted{color:var(--sd-color-muted) !important;border-color:var(--sd-color-muted) !important;border-width:1px !important;border-style:solid !important}.sd-btn-dark,.sd-btn-outline-dark:hover,.sd-btn-outline-dark:focus{color:var(--sd-color-dark-text) !important;background-color:var(--sd-color-dark) !important;border-color:var(--sd-color-dark) !important;border-width:1px !important;border-style:solid !important}.sd-btn-dark:hover,.sd-btn-dark:focus{color:var(--sd-color-dark-text) !important;background-color:var(--sd-color-dark-highlight) !important;border-color:var(--sd-color-dark-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-dark{color:var(--sd-color-dark) !important;border-color:var(--sd-color-dark) !important;border-width:1px !important;border-style:solid !important}.sd-btn-black,.sd-btn-outline-black:hover,.sd-btn-outline-black:focus{color:var(--sd-color-black-text) !important;background-color:var(--sd-color-black) !important;border-color:var(--sd-color-black) !important;border-width:1px !important;border-style:solid !important}.sd-btn-black:hover,.sd-btn-black:focus{color:var(--sd-color-black-text) !important;background-color:var(--sd-color-black-highlight) !important;border-color:var(--sd-color-black-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-black{color:var(--sd-color-black) !important;border-color:var(--sd-color-black) !important;border-width:1px !important;border-style:solid !important}.sd-btn-white,.sd-btn-outline-white:hover,.sd-btn-outline-white:focus{color:var(--sd-color-white-text) !important;background-color:var(--sd-color-white) !important;border-color:var(--sd-color-white) !important;border-width:1px !important;border-style:solid !important}.sd-btn-white:hover,.sd-btn-white:focus{color:var(--sd-color-white-text) !important;background-color:var(--sd-color-white-highlight) !important;border-color:var(--sd-color-white-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-white{color:var(--sd-color-white) !important;border-color:var(--sd-color-white) !important;border-width:1px !important;border-style:solid !important}.sd-stretched-link::after{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;content:""}.sd-hide-link-text{font-size:0}.sd-octicon,.sd-material-icon{display:inline-block;fill:currentColor;vertical-align:middle}.sd-avatar-xs{border-radius:50%;object-fit:cover;object-position:center;width:1rem;height:1rem}.sd-avatar-sm{border-radius:50%;object-fit:cover;object-position:center;width:3rem;height:3rem}.sd-avatar-md{border-radius:50%;object-fit:cover;object-position:center;width:5rem;height:5rem}.sd-avatar-lg{border-radius:50%;object-fit:cover;object-position:center;width:7rem;height:7rem}.sd-avatar-xl{border-radius:50%;object-fit:cover;object-position:center;width:10rem;height:10rem}.sd-avatar-inherit{border-radius:50%;object-fit:cover;object-position:center;width:inherit;height:inherit}.sd-avatar-initial{border-radius:50%;object-fit:cover;object-position:center;width:initial;height:initial}.sd-card{background-clip:border-box;background-color:var(--sd-color-card-background);border:1px solid var(--sd-color-card-border);border-radius:.25rem;color:var(--sd-color-card-text);display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;min-width:0;position:relative;word-wrap:break-word}.sd-card>hr{margin-left:0;margin-right:0}.sd-card-hover:hover{border-color:var(--sd-color-card-border-hover);transform:scale(1.01)}.sd-card-body{-ms-flex:1 1 auto;flex:1 1 auto;padding:1rem 1rem}.sd-card-title{margin-bottom:.5rem}.sd-card-subtitle{margin-top:-0.25rem;margin-bottom:0}.sd-card-text:last-child{margin-bottom:0}.sd-card-link:hover{text-decoration:none}.sd-card-link+.card-link{margin-left:1rem}.sd-card-header{padding:.5rem 1rem;margin-bottom:0;background-color:var(--sd-color-card-header);border-bottom:1px solid var(--sd-color-card-border)}.sd-card-header:first-child{border-radius:calc(0.25rem - 1px) calc(0.25rem - 1px) 0 0}.sd-card-footer{padding:.5rem 1rem;background-color:var(--sd-color-card-footer);border-top:1px solid var(--sd-color-card-border)}.sd-card-footer:last-child{border-radius:0 0 calc(0.25rem - 1px) calc(0.25rem - 1px)}.sd-card-header-tabs{margin-right:-0.5rem;margin-bottom:-0.5rem;margin-left:-0.5rem;border-bottom:0}.sd-card-header-pills{margin-right:-0.5rem;margin-left:-0.5rem}.sd-card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1rem;border-radius:calc(0.25rem - 1px)}.sd-card-img,.sd-card-img-bottom,.sd-card-img-top{width:100%}.sd-card-img,.sd-card-img-top{border-top-left-radius:calc(0.25rem - 1px);border-top-right-radius:calc(0.25rem - 1px)}.sd-card-img,.sd-card-img-bottom{border-bottom-left-radius:calc(0.25rem - 1px);border-bottom-right-radius:calc(0.25rem - 1px)}.sd-cards-carousel{width:100%;display:flex;flex-wrap:nowrap;-ms-flex-direction:row;flex-direction:row;overflow-x:hidden;scroll-snap-type:x mandatory}.sd-cards-carousel.sd-show-scrollbar{overflow-x:auto}.sd-cards-carousel:hover,.sd-cards-carousel:focus{overflow-x:auto}.sd-cards-carousel>.sd-card{flex-shrink:0;scroll-snap-align:start}.sd-cards-carousel>.sd-card:not(:last-child){margin-right:3px}.sd-card-cols-1>.sd-card{width:90%}.sd-card-cols-2>.sd-card{width:45%}.sd-card-cols-3>.sd-card{width:30%}.sd-card-cols-4>.sd-card{width:22.5%}.sd-card-cols-5>.sd-card{width:18%}.sd-card-cols-6>.sd-card{width:15%}.sd-card-cols-7>.sd-card{width:12.8571428571%}.sd-card-cols-8>.sd-card{width:11.25%}.sd-card-cols-9>.sd-card{width:10%}.sd-card-cols-10>.sd-card{width:9%}.sd-card-cols-11>.sd-card{width:8.1818181818%}.sd-card-cols-12>.sd-card{width:7.5%}.sd-container,.sd-container-fluid,.sd-container-lg,.sd-container-md,.sd-container-sm,.sd-container-xl{margin-left:auto;margin-right:auto;padding-left:var(--sd-gutter-x, 0.75rem);padding-right:var(--sd-gutter-x, 0.75rem);width:100%}@media(min-width: 576px){.sd-container-sm,.sd-container{max-width:540px}}@media(min-width: 768px){.sd-container-md,.sd-container-sm,.sd-container{max-width:720px}}@media(min-width: 992px){.sd-container-lg,.sd-container-md,.sd-container-sm,.sd-container{max-width:960px}}@media(min-width: 1200px){.sd-container-xl,.sd-container-lg,.sd-container-md,.sd-container-sm,.sd-container{max-width:1140px}}.sd-row{--sd-gutter-x: 1.5rem;--sd-gutter-y: 0;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-top:calc(var(--sd-gutter-y) * -1);margin-right:calc(var(--sd-gutter-x) * -0.5);margin-left:calc(var(--sd-gutter-x) * -0.5)}.sd-row>*{box-sizing:border-box;flex-shrink:0;width:100%;max-width:100%;padding-right:calc(var(--sd-gutter-x) * 0.5);padding-left:calc(var(--sd-gutter-x) * 0.5);margin-top:var(--sd-gutter-y)}.sd-col{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-auto>*{flex:0 0 auto;width:auto}.sd-row-cols-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}@media(min-width: 576px){.sd-col-sm{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-sm-auto{flex:1 0 auto;-ms-flex:1 0 auto;width:100%}.sd-row-cols-sm-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-sm-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-sm-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-sm-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-sm-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-sm-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-sm-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-sm-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-sm-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-sm-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-sm-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-sm-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}}@media(min-width: 768px){.sd-col-md{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-md-auto{flex:1 0 auto;-ms-flex:1 0 auto;width:100%}.sd-row-cols-md-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-md-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-md-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-md-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-md-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-md-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-md-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-md-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-md-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-md-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-md-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-md-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}}@media(min-width: 992px){.sd-col-lg{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-lg-auto{flex:1 0 auto;-ms-flex:1 0 auto;width:100%}.sd-row-cols-lg-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-lg-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-lg-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-lg-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-lg-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-lg-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-lg-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-lg-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-lg-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-lg-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-lg-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-lg-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}}@media(min-width: 1200px){.sd-col-xl{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-xl-auto{flex:1 0 auto;-ms-flex:1 0 auto;width:100%}.sd-row-cols-xl-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-xl-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-xl-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-xl-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-xl-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-xl-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-xl-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-xl-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-xl-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-xl-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-xl-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-xl-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}}.sd-col-auto{flex:0 0 auto;-ms-flex:0 0 auto;width:auto}.sd-col-1{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}.sd-col-2{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-col-3{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-col-4{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-col-5{flex:0 0 auto;-ms-flex:0 0 auto;width:41.6666666667%}.sd-col-6{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-col-7{flex:0 0 auto;-ms-flex:0 0 auto;width:58.3333333333%}.sd-col-8{flex:0 0 auto;-ms-flex:0 0 auto;width:66.6666666667%}.sd-col-9{flex:0 0 auto;-ms-flex:0 0 auto;width:75%}.sd-col-10{flex:0 0 auto;-ms-flex:0 0 auto;width:83.3333333333%}.sd-col-11{flex:0 0 auto;-ms-flex:0 0 auto;width:91.6666666667%}.sd-col-12{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-g-0,.sd-gy-0{--sd-gutter-y: 0}.sd-g-0,.sd-gx-0{--sd-gutter-x: 0}.sd-g-1,.sd-gy-1{--sd-gutter-y: 0.25rem}.sd-g-1,.sd-gx-1{--sd-gutter-x: 0.25rem}.sd-g-2,.sd-gy-2{--sd-gutter-y: 0.5rem}.sd-g-2,.sd-gx-2{--sd-gutter-x: 0.5rem}.sd-g-3,.sd-gy-3{--sd-gutter-y: 1rem}.sd-g-3,.sd-gx-3{--sd-gutter-x: 1rem}.sd-g-4,.sd-gy-4{--sd-gutter-y: 1.5rem}.sd-g-4,.sd-gx-4{--sd-gutter-x: 1.5rem}.sd-g-5,.sd-gy-5{--sd-gutter-y: 3rem}.sd-g-5,.sd-gx-5{--sd-gutter-x: 3rem}@media(min-width: 576px){.sd-col-sm-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto}.sd-col-sm-1{-ms-flex:0 0 auto;flex:0 0 auto;width:8.3333333333%}.sd-col-sm-2{-ms-flex:0 0 auto;flex:0 0 auto;width:16.6666666667%}.sd-col-sm-3{-ms-flex:0 0 auto;flex:0 0 auto;width:25%}.sd-col-sm-4{-ms-flex:0 0 auto;flex:0 0 auto;width:33.3333333333%}.sd-col-sm-5{-ms-flex:0 0 auto;flex:0 0 auto;width:41.6666666667%}.sd-col-sm-6{-ms-flex:0 0 auto;flex:0 0 auto;width:50%}.sd-col-sm-7{-ms-flex:0 0 auto;flex:0 0 auto;width:58.3333333333%}.sd-col-sm-8{-ms-flex:0 0 auto;flex:0 0 auto;width:66.6666666667%}.sd-col-sm-9{-ms-flex:0 0 auto;flex:0 0 auto;width:75%}.sd-col-sm-10{-ms-flex:0 0 auto;flex:0 0 auto;width:83.3333333333%}.sd-col-sm-11{-ms-flex:0 0 auto;flex:0 0 auto;width:91.6666666667%}.sd-col-sm-12{-ms-flex:0 0 auto;flex:0 0 auto;width:100%}.sd-g-sm-0,.sd-gy-sm-0{--sd-gutter-y: 0}.sd-g-sm-0,.sd-gx-sm-0{--sd-gutter-x: 0}.sd-g-sm-1,.sd-gy-sm-1{--sd-gutter-y: 0.25rem}.sd-g-sm-1,.sd-gx-sm-1{--sd-gutter-x: 0.25rem}.sd-g-sm-2,.sd-gy-sm-2{--sd-gutter-y: 0.5rem}.sd-g-sm-2,.sd-gx-sm-2{--sd-gutter-x: 0.5rem}.sd-g-sm-3,.sd-gy-sm-3{--sd-gutter-y: 1rem}.sd-g-sm-3,.sd-gx-sm-3{--sd-gutter-x: 1rem}.sd-g-sm-4,.sd-gy-sm-4{--sd-gutter-y: 1.5rem}.sd-g-sm-4,.sd-gx-sm-4{--sd-gutter-x: 1.5rem}.sd-g-sm-5,.sd-gy-sm-5{--sd-gutter-y: 3rem}.sd-g-sm-5,.sd-gx-sm-5{--sd-gutter-x: 3rem}}@media(min-width: 768px){.sd-col-md-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto}.sd-col-md-1{-ms-flex:0 0 auto;flex:0 0 auto;width:8.3333333333%}.sd-col-md-2{-ms-flex:0 0 auto;flex:0 0 auto;width:16.6666666667%}.sd-col-md-3{-ms-flex:0 0 auto;flex:0 0 auto;width:25%}.sd-col-md-4{-ms-flex:0 0 auto;flex:0 0 auto;width:33.3333333333%}.sd-col-md-5{-ms-flex:0 0 auto;flex:0 0 auto;width:41.6666666667%}.sd-col-md-6{-ms-flex:0 0 auto;flex:0 0 auto;width:50%}.sd-col-md-7{-ms-flex:0 0 auto;flex:0 0 auto;width:58.3333333333%}.sd-col-md-8{-ms-flex:0 0 auto;flex:0 0 auto;width:66.6666666667%}.sd-col-md-9{-ms-flex:0 0 auto;flex:0 0 auto;width:75%}.sd-col-md-10{-ms-flex:0 0 auto;flex:0 0 auto;width:83.3333333333%}.sd-col-md-11{-ms-flex:0 0 auto;flex:0 0 auto;width:91.6666666667%}.sd-col-md-12{-ms-flex:0 0 auto;flex:0 0 auto;width:100%}.sd-g-md-0,.sd-gy-md-0{--sd-gutter-y: 0}.sd-g-md-0,.sd-gx-md-0{--sd-gutter-x: 0}.sd-g-md-1,.sd-gy-md-1{--sd-gutter-y: 0.25rem}.sd-g-md-1,.sd-gx-md-1{--sd-gutter-x: 0.25rem}.sd-g-md-2,.sd-gy-md-2{--sd-gutter-y: 0.5rem}.sd-g-md-2,.sd-gx-md-2{--sd-gutter-x: 0.5rem}.sd-g-md-3,.sd-gy-md-3{--sd-gutter-y: 1rem}.sd-g-md-3,.sd-gx-md-3{--sd-gutter-x: 1rem}.sd-g-md-4,.sd-gy-md-4{--sd-gutter-y: 1.5rem}.sd-g-md-4,.sd-gx-md-4{--sd-gutter-x: 1.5rem}.sd-g-md-5,.sd-gy-md-5{--sd-gutter-y: 3rem}.sd-g-md-5,.sd-gx-md-5{--sd-gutter-x: 3rem}}@media(min-width: 992px){.sd-col-lg-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto}.sd-col-lg-1{-ms-flex:0 0 auto;flex:0 0 auto;width:8.3333333333%}.sd-col-lg-2{-ms-flex:0 0 auto;flex:0 0 auto;width:16.6666666667%}.sd-col-lg-3{-ms-flex:0 0 auto;flex:0 0 auto;width:25%}.sd-col-lg-4{-ms-flex:0 0 auto;flex:0 0 auto;width:33.3333333333%}.sd-col-lg-5{-ms-flex:0 0 auto;flex:0 0 auto;width:41.6666666667%}.sd-col-lg-6{-ms-flex:0 0 auto;flex:0 0 auto;width:50%}.sd-col-lg-7{-ms-flex:0 0 auto;flex:0 0 auto;width:58.3333333333%}.sd-col-lg-8{-ms-flex:0 0 auto;flex:0 0 auto;width:66.6666666667%}.sd-col-lg-9{-ms-flex:0 0 auto;flex:0 0 auto;width:75%}.sd-col-lg-10{-ms-flex:0 0 auto;flex:0 0 auto;width:83.3333333333%}.sd-col-lg-11{-ms-flex:0 0 auto;flex:0 0 auto;width:91.6666666667%}.sd-col-lg-12{-ms-flex:0 0 auto;flex:0 0 auto;width:100%}.sd-g-lg-0,.sd-gy-lg-0{--sd-gutter-y: 0}.sd-g-lg-0,.sd-gx-lg-0{--sd-gutter-x: 0}.sd-g-lg-1,.sd-gy-lg-1{--sd-gutter-y: 0.25rem}.sd-g-lg-1,.sd-gx-lg-1{--sd-gutter-x: 0.25rem}.sd-g-lg-2,.sd-gy-lg-2{--sd-gutter-y: 0.5rem}.sd-g-lg-2,.sd-gx-lg-2{--sd-gutter-x: 0.5rem}.sd-g-lg-3,.sd-gy-lg-3{--sd-gutter-y: 1rem}.sd-g-lg-3,.sd-gx-lg-3{--sd-gutter-x: 1rem}.sd-g-lg-4,.sd-gy-lg-4{--sd-gutter-y: 1.5rem}.sd-g-lg-4,.sd-gx-lg-4{--sd-gutter-x: 1.5rem}.sd-g-lg-5,.sd-gy-lg-5{--sd-gutter-y: 3rem}.sd-g-lg-5,.sd-gx-lg-5{--sd-gutter-x: 3rem}}@media(min-width: 1200px){.sd-col-xl-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto}.sd-col-xl-1{-ms-flex:0 0 auto;flex:0 0 auto;width:8.3333333333%}.sd-col-xl-2{-ms-flex:0 0 auto;flex:0 0 auto;width:16.6666666667%}.sd-col-xl-3{-ms-flex:0 0 auto;flex:0 0 auto;width:25%}.sd-col-xl-4{-ms-flex:0 0 auto;flex:0 0 auto;width:33.3333333333%}.sd-col-xl-5{-ms-flex:0 0 auto;flex:0 0 auto;width:41.6666666667%}.sd-col-xl-6{-ms-flex:0 0 auto;flex:0 0 auto;width:50%}.sd-col-xl-7{-ms-flex:0 0 auto;flex:0 0 auto;width:58.3333333333%}.sd-col-xl-8{-ms-flex:0 0 auto;flex:0 0 auto;width:66.6666666667%}.sd-col-xl-9{-ms-flex:0 0 auto;flex:0 0 auto;width:75%}.sd-col-xl-10{-ms-flex:0 0 auto;flex:0 0 auto;width:83.3333333333%}.sd-col-xl-11{-ms-flex:0 0 auto;flex:0 0 auto;width:91.6666666667%}.sd-col-xl-12{-ms-flex:0 0 auto;flex:0 0 auto;width:100%}.sd-g-xl-0,.sd-gy-xl-0{--sd-gutter-y: 0}.sd-g-xl-0,.sd-gx-xl-0{--sd-gutter-x: 0}.sd-g-xl-1,.sd-gy-xl-1{--sd-gutter-y: 0.25rem}.sd-g-xl-1,.sd-gx-xl-1{--sd-gutter-x: 0.25rem}.sd-g-xl-2,.sd-gy-xl-2{--sd-gutter-y: 0.5rem}.sd-g-xl-2,.sd-gx-xl-2{--sd-gutter-x: 0.5rem}.sd-g-xl-3,.sd-gy-xl-3{--sd-gutter-y: 1rem}.sd-g-xl-3,.sd-gx-xl-3{--sd-gutter-x: 1rem}.sd-g-xl-4,.sd-gy-xl-4{--sd-gutter-y: 1.5rem}.sd-g-xl-4,.sd-gx-xl-4{--sd-gutter-x: 1.5rem}.sd-g-xl-5,.sd-gy-xl-5{--sd-gutter-y: 3rem}.sd-g-xl-5,.sd-gx-xl-5{--sd-gutter-x: 3rem}}.sd-flex-row-reverse{flex-direction:row-reverse !important}details.sd-dropdown{position:relative}details.sd-dropdown .sd-summary-title{font-weight:700;padding-right:3em !important;-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none;user-select:none}details.sd-dropdown:hover{cursor:pointer}details.sd-dropdown .sd-summary-content{cursor:default}details.sd-dropdown summary{list-style:none;padding:1em}details.sd-dropdown summary .sd-octicon.no-title{vertical-align:middle}details.sd-dropdown[open] summary .sd-octicon.no-title{visibility:hidden}details.sd-dropdown summary::-webkit-details-marker{display:none}details.sd-dropdown summary:focus{outline:none}details.sd-dropdown .sd-summary-icon{margin-right:.5em}details.sd-dropdown .sd-summary-icon svg{opacity:.8}details.sd-dropdown summary:hover .sd-summary-up svg,details.sd-dropdown summary:hover .sd-summary-down svg{opacity:1;transform:scale(1.1)}details.sd-dropdown .sd-summary-up svg,details.sd-dropdown .sd-summary-down svg{display:block;opacity:.6}details.sd-dropdown .sd-summary-up,details.sd-dropdown .sd-summary-down{pointer-events:none;position:absolute;right:1em;top:1em}details.sd-dropdown[open]>.sd-summary-title .sd-summary-down{visibility:hidden}details.sd-dropdown:not([open])>.sd-summary-title .sd-summary-up{visibility:hidden}details.sd-dropdown:not([open]).sd-card{border:none}details.sd-dropdown:not([open])>.sd-card-header{border:1px solid var(--sd-color-card-border);border-radius:.25rem}details.sd-dropdown.sd-fade-in[open] summary~*{-moz-animation:sd-fade-in .5s ease-in-out;-webkit-animation:sd-fade-in .5s ease-in-out;animation:sd-fade-in .5s ease-in-out}details.sd-dropdown.sd-fade-in-slide-down[open] summary~*{-moz-animation:sd-fade-in .5s ease-in-out,sd-slide-down .5s ease-in-out;-webkit-animation:sd-fade-in .5s ease-in-out,sd-slide-down .5s ease-in-out;animation:sd-fade-in .5s ease-in-out,sd-slide-down .5s ease-in-out}.sd-col>.sd-dropdown{width:100%}.sd-summary-content>.sd-tab-set:first-child{margin-top:0}@keyframes sd-fade-in{0%{opacity:0}100%{opacity:1}}@keyframes sd-slide-down{0%{transform:translate(0, -10px)}100%{transform:translate(0, 0)}}.sd-tab-set{border-radius:.125rem;display:flex;flex-wrap:wrap;margin:1em 0;position:relative}.sd-tab-set>input{opacity:0;position:absolute}.sd-tab-set>input:checked+label{border-color:var(--sd-color-tabs-underline-active);color:var(--sd-color-tabs-label-active)}.sd-tab-set>input:checked+label+.sd-tab-content{display:block}.sd-tab-set>input:not(:checked)+label:hover{color:var(--sd-color-tabs-label-hover);border-color:var(--sd-color-tabs-underline-hover)}.sd-tab-set>input:focus+label{outline-style:auto}.sd-tab-set>input:not(.focus-visible)+label{outline:none;-webkit-tap-highlight-color:transparent}.sd-tab-set>label{border-bottom:.125rem solid transparent;margin-bottom:0;color:var(--sd-color-tabs-label-inactive);border-color:var(--sd-color-tabs-underline-inactive);cursor:pointer;font-size:var(--sd-fontsize-tabs-label);font-weight:700;padding:1em 1.25em .5em;transition:color 250ms;width:auto;z-index:1}html .sd-tab-set>label:hover{color:var(--sd-color-tabs-label-active)}.sd-col>.sd-tab-set{width:100%}.sd-tab-content{box-shadow:0 -0.0625rem var(--sd-color-tabs-overline),0 .0625rem var(--sd-color-tabs-underline);display:none;order:99;padding-bottom:.75rem;padding-top:.75rem;width:100%}.sd-tab-content>:first-child{margin-top:0 !important}.sd-tab-content>:last-child{margin-bottom:0 !important}.sd-tab-content>.sd-tab-set{margin:0}.sd-sphinx-override,.sd-sphinx-override *{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}.sd-sphinx-override p{margin-top:0}:root{--sd-color-primary: #0071bc;--sd-color-secondary: #6c757d;--sd-color-success: #28a745;--sd-color-info: #17a2b8;--sd-color-warning: #f0b37e;--sd-color-danger: #dc3545;--sd-color-light: #f8f9fa;--sd-color-muted: #6c757d;--sd-color-dark: #212529;--sd-color-black: black;--sd-color-white: white;--sd-color-primary-highlight: #0060a0;--sd-color-secondary-highlight: #5c636a;--sd-color-success-highlight: #228e3b;--sd-color-info-highlight: #148a9c;--sd-color-warning-highlight: #cc986b;--sd-color-danger-highlight: #bb2d3b;--sd-color-light-highlight: #d3d4d5;--sd-color-muted-highlight: #5c636a;--sd-color-dark-highlight: #1c1f23;--sd-color-black-highlight: black;--sd-color-white-highlight: #d9d9d9;--sd-color-primary-text: #fff;--sd-color-secondary-text: #fff;--sd-color-success-text: #fff;--sd-color-info-text: #fff;--sd-color-warning-text: #212529;--sd-color-danger-text: #fff;--sd-color-light-text: #212529;--sd-color-muted-text: #fff;--sd-color-dark-text: #fff;--sd-color-black-text: #fff;--sd-color-white-text: #212529;--sd-color-shadow: rgba(0, 0, 0, 0.15);--sd-color-card-border: rgba(0, 0, 0, 0.125);--sd-color-card-border-hover: hsla(231, 99%, 66%, 1);--sd-color-card-background: transparent;--sd-color-card-text: inherit;--sd-color-card-header: transparent;--sd-color-card-footer: transparent;--sd-color-tabs-label-active: hsla(231, 99%, 66%, 1);--sd-color-tabs-label-hover: hsla(231, 99%, 66%, 1);--sd-color-tabs-label-inactive: hsl(0, 0%, 66%);--sd-color-tabs-underline-active: hsla(231, 99%, 66%, 1);--sd-color-tabs-underline-hover: rgba(178, 206, 245, 0.62);--sd-color-tabs-underline-inactive: transparent;--sd-color-tabs-overline: rgb(222, 222, 222);--sd-color-tabs-underline: rgb(222, 222, 222);--sd-fontsize-tabs-label: 1rem} diff --git a/_sphinx_design_static/design-tabs.js b/_sphinx_design_static/design-tabs.js new file mode 100644 index 0000000..36b38cf --- /dev/null +++ b/_sphinx_design_static/design-tabs.js @@ -0,0 +1,27 @@ +var sd_labels_by_text = {}; + +function ready() { + const li = document.getElementsByClassName("sd-tab-label"); + for (const label of li) { + syncId = label.getAttribute("data-sync-id"); + if (syncId) { + label.onclick = onLabelClick; + if (!sd_labels_by_text[syncId]) { + sd_labels_by_text[syncId] = []; + } + sd_labels_by_text[syncId].push(label); + } + } +} + +function onLabelClick() { + // Activate other inputs with the same sync id. + syncId = this.getAttribute("data-sync-id"); + for (label of sd_labels_by_text[syncId]) { + if (label === this) continue; + label.previousElementSibling.checked = true; + } + window.localStorage.setItem("sphinx-design-last-tab", syncId); +} + +document.addEventListener("DOMContentLoaded", ready, false); diff --git a/_static/_sphinx_javascript_frameworks_compat.js b/_static/_sphinx_javascript_frameworks_compat.js new file mode 100644 index 0000000..8549469 --- /dev/null +++ b/_static/_sphinx_javascript_frameworks_compat.js @@ -0,0 +1,134 @@ +/* + * _sphinx_javascript_frameworks_compat.js + * ~~~~~~~~~~ + * + * Compatability shim for jQuery and underscores.js. + * + * WILL BE REMOVED IN Sphinx 6.0 + * xref RemovedInSphinx60Warning + * + */ + +/** + * select a different prefix for underscore + */ +$u = _.noConflict(); + + +/** + * small helper function to urldecode strings + * + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent#Decoding_query_parameters_from_a_URL + */ +jQuery.urldecode = function(x) { + if (!x) { + return x + } + return decodeURIComponent(x.replace(/\+/g, ' ')); +}; + +/** + * small helper function to urlencode strings + */ +jQuery.urlencode = encodeURIComponent; + +/** + * This function returns the parsed url parameters of the + * current request. Multiple values per key are supported, + * it will always return arrays of strings for the value parts. + */ +jQuery.getQueryParameters = function(s) { + if (typeof s === 'undefined') + s = document.location.search; + var parts = s.substr(s.indexOf('?') + 1).split('&'); + var result = {}; + for (var i = 0; i < parts.length; i++) { + var tmp = parts[i].split('=', 2); + var key = jQuery.urldecode(tmp[0]); + var value = jQuery.urldecode(tmp[1]); + if (key in result) + result[key].push(value); + else + result[key] = [value]; + } + return result; +}; + +/** + * highlight a given string on a jquery object by wrapping it in + * span elements with the given class name. + */ +jQuery.fn.highlightText = function(text, className) { + function highlight(node, addItems) { + if (node.nodeType === 3) { + var val = node.nodeValue; + var pos = val.toLowerCase().indexOf(text); + if (pos >= 0 && + !jQuery(node.parentNode).hasClass(className) && + !jQuery(node.parentNode).hasClass("nohighlight")) { + var span; + var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.className = className; + } + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + node.parentNode.insertBefore(span, node.parentNode.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling)); + node.nodeValue = val.substr(0, pos); + if (isInSVG) { + var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); + var bbox = node.parentElement.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute('class', className); + addItems.push({ + "parent": node.parentNode, + "target": rect}); + } + } + } + else if (!jQuery(node).is("button, select, textarea")) { + jQuery.each(node.childNodes, function() { + highlight(this, addItems); + }); + } + } + var addItems = []; + var result = this.each(function() { + highlight(this, addItems); + }); + for (var i = 0; i < addItems.length; ++i) { + jQuery(addItems[i].parent).before(addItems[i].target); + } + return result; +}; + +/* + * backward compatibility for jQuery.browser + * This will be supported until firefox bug is fixed. + */ +if (!jQuery.browser) { + jQuery.uaMatch = function(ua) { + ua = ua.toLowerCase(); + + var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || + /(webkit)[ \/]([\w.]+)/.exec(ua) || + /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || + /(msie) ([\w.]+)/.exec(ua) || + ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || + []; + + return { + browser: match[ 1 ] || "", + version: match[ 2 ] || "0" + }; + }; + jQuery.browser = {}; + jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; +} diff --git a/_static/alert.css b/_static/alert.css new file mode 100644 index 0000000..a818895 --- /dev/null +++ b/_static/alert.css @@ -0,0 +1,78 @@ +.alert { + padding: 0.75rem 1.25rem; + margin-bottom: 1rem; + border: 1px solid transparent; + border-radius: 0.25rem; +} + +.alert-heading { + color: inherit; +} + +.alert-link { + font-weight: bold; +} + +.alert-dismissible .close { + position: relative; + top: -0.75rem; + right: -1.25rem; + padding: 0.75rem 1.25rem; + color: inherit; +} + +.alert-success { + background-color: #dff0d8; + border-color: #d0e9c6; + color: #3c763d; +} + +.alert-success hr { + border-top-color: #c1e2b3; +} + +.alert-success .alert-link { + color: #2b542c; +} + +.alert-info { + background-color: #d9edf7; + border-color: #bcdff1; + color: #31708f; +} + +.alert-info hr { + border-top-color: #a6d5ec; +} + +.alert-info .alert-link { + color: #245269; +} + +.alert-warning { + background-color: #fcf8e3; + border-color: #faf2cc; + color: #8a6d3b; +} + +.alert-warning hr { + border-top-color: #f7ecb5; +} + +.alert-warning .alert-link { + color: #66512c; +} + +.alert-danger { + background-color: #f2dede; + border-color: #ebcccc; + color: #a94442; +} + +.alert-danger hr { + border-top-color: #e4b9b9; +} + +.alert-danger .alert-link { + color: #843534; +} diff --git a/_static/basic.css b/_static/basic.css new file mode 100644 index 0000000..18495ea --- /dev/null +++ b/_static/basic.css @@ -0,0 +1,900 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2022 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +div.section::after { + display: block; + content: ''; + clear: left; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 270px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox form.search { + overflow: hidden; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li p.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: 360px; + max-width: 800px; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, figure.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, figure.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, figure.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +img.align-default, figure.align-default, .figure.align-default { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-default { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar, +aside.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px; + background-color: #ffe; + width: 40%; + float: right; + clear: right; + overflow-x: auto; +} + +p.sidebar-title { + font-weight: bold; +} +nav.contents, +aside.topic, +div.admonition, div.topic, blockquote { + clear: left; +} + +/* -- topics ---------------------------------------------------------------- */ +nav.contents, +aside.topic, +div.topic { + border: 1px solid #ccc; + padding: 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- content of sidebars/topics/admonitions -------------------------------- */ + +div.sidebar > :last-child, +aside.sidebar > :last-child, +nav.contents > :last-child, +aside.topic > :last-child, +div.topic > :last-child, +div.admonition > :last-child { + margin-bottom: 0; +} + +div.sidebar::after, +aside.sidebar::after, +nav.contents::after, +aside.topic::after, +div.topic::after, +div.admonition::after, +blockquote::after { + display: block; + content: ''; + clear: both; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + margin-top: 10px; + margin-bottom: 10px; + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table.align-default { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +th > :first-child, +td > :first-child { + margin-top: 0px; +} + +th > :last-child, +td > :last-child { + margin-bottom: 0px; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure, figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption, figcaption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number, +figcaption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text, +figcaption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- hlist styles ---------------------------------------------------------- */ + +table.hlist { + margin: 1em 0; +} + +table.hlist td { + vertical-align: top; +} + +/* -- object description styles --------------------------------------------- */ + +.sig { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; +} + +.sig-name, code.descname { + background-color: transparent; + font-weight: bold; +} + +.sig-name { + font-size: 1.1em; +} + +code.descname { + font-size: 1.2em; +} + +.sig-prename, code.descclassname { + background-color: transparent; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.sig-param.n { + font-style: italic; +} + +/* C++ specific styling */ + +.sig-inline.c-texpr, +.sig-inline.cpp-texpr { + font-family: unset; +} + +.sig.c .k, .sig.c .kt, +.sig.cpp .k, .sig.cpp .kt { + color: #0033B3; +} + +.sig.c .m, +.sig.cpp .m { + color: #1750EB; +} + +.sig.c .s, .sig.c .sc, +.sig.cpp .s, .sig.cpp .sc { + color: #067D17; +} + + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +:not(li) > ol > li:first-child > :first-child, +:not(li) > ul > li:first-child > :first-child { + margin-top: 0px; +} + +:not(li) > ol > li:last-child > :last-child, +:not(li) > ul > li:last-child > :last-child { + margin-bottom: 0px; +} + +ol.simple ol p, +ol.simple ul p, +ul.simple ol p, +ul.simple ul p { + margin-top: 0; +} + +ol.simple > li:not(:first-child) > p, +ul.simple > li:not(:first-child) > p { + margin-top: 0; +} + +ol.simple p, +ul.simple p { + margin-bottom: 0; +} +aside.footnote > span, +div.citation > span { + float: left; +} +aside.footnote > span:last-of-type, +div.citation > span:last-of-type { + padding-right: 0.5em; +} +aside.footnote > p { + margin-left: 2em; +} +div.citation > p { + margin-left: 4em; +} +aside.footnote > p:last-of-type, +div.citation > p:last-of-type { + margin-bottom: 0em; +} +aside.footnote > p:last-of-type:after, +div.citation > p:last-of-type:after { + content: ""; + clear: both; +} + +dl.field-list { + display: grid; + grid-template-columns: fit-content(30%) auto; +} + +dl.field-list > dt { + font-weight: bold; + word-break: break-word; + padding-left: 0.5em; + padding-right: 5px; +} + +dl.field-list > dd { + padding-left: 0.5em; + margin-top: 0em; + margin-left: 0em; + margin-bottom: 0em; +} + +dl { + margin-bottom: 15px; +} + +dd > :first-child { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +dl > dd:last-child, +dl > dd:last-child > :last-child { + margin-bottom: 0; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +.classifier:before { + font-style: normal; + margin: 0 0.5em; + content: ":"; + display: inline-block; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +pre, div[class*="highlight-"] { + clear: both; +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; + white-space: nowrap; +} + +div[class*="highlight-"] { + margin: 1em 0; +} + +td.linenos pre { + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + display: block; +} + +table.highlighttable tbody { + display: block; +} + +table.highlighttable tr { + display: flex; +} + +table.highlighttable td { + margin: 0; + padding: 0; +} + +table.highlighttable td.linenos { + padding-right: 0.5em; +} + +table.highlighttable td.code { + flex: 1; + overflow: hidden; +} + +.highlight .hll { + display: block; +} + +div.highlight pre, +table.highlighttable pre { + margin: 0; +} + +div.code-block-caption + div { + margin-top: 0; +} + +div.code-block-caption { + margin-top: 1em; + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +table.highlighttable td.linenos, +span.linenos, +div.highlight span.gp { /* gp: Generic.Prompt */ + user-select: none; + -webkit-user-select: text; /* Safari fallback only */ + -webkit-user-select: none; /* Chrome/Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* IE10+ */ +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + margin: 1em 0; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: absolute; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/_static/check-solid.svg b/_static/check-solid.svg new file mode 100644 index 0000000..92fad4b --- /dev/null +++ b/_static/check-solid.svg @@ -0,0 +1,4 @@ + + + + diff --git a/_static/clipboard.min.js b/_static/clipboard.min.js new file mode 100644 index 0000000..54b3c46 --- /dev/null +++ b/_static/clipboard.min.js @@ -0,0 +1,7 @@ +/*! + * clipboard.js v2.0.8 + * https://clipboardjs.com/ + * + * Licensed MIT © Zeno Rocha + */ +!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ClipboardJS=e():t.ClipboardJS=e()}(this,function(){return n={686:function(t,e,n){"use strict";n.d(e,{default:function(){return o}});var e=n(279),i=n.n(e),e=n(370),u=n.n(e),e=n(817),c=n.n(e);function a(t){try{return document.execCommand(t)}catch(t){return}}var f=function(t){t=c()(t);return a("cut"),t};var l=function(t){var e,n,o,r=1 + + + + diff --git a/_static/copybutton.css b/_static/copybutton.css new file mode 100644 index 0000000..f1916ec --- /dev/null +++ b/_static/copybutton.css @@ -0,0 +1,94 @@ +/* Copy buttons */ +button.copybtn { + position: absolute; + display: flex; + top: .3em; + right: .3em; + width: 1.7em; + height: 1.7em; + opacity: 0; + transition: opacity 0.3s, border .3s, background-color .3s; + user-select: none; + padding: 0; + border: none; + outline: none; + border-radius: 0.4em; + /* The colors that GitHub uses */ + border: #1b1f2426 1px solid; + background-color: #f6f8fa; + color: #57606a; +} + +button.copybtn.success { + border-color: #22863a; + color: #22863a; +} + +button.copybtn svg { + stroke: currentColor; + width: 1.5em; + height: 1.5em; + padding: 0.1em; +} + +div.highlight { + position: relative; +} + +/* Show the copybutton */ +.highlight:hover button.copybtn, button.copybtn.success { + opacity: 1; +} + +.highlight button.copybtn:hover { + background-color: rgb(235, 235, 235); +} + +.highlight button.copybtn:active { + background-color: rgb(187, 187, 187); +} + +/** + * A minimal CSS-only tooltip copied from: + * https://codepen.io/mildrenben/pen/rVBrpK + * + * To use, write HTML like the following: + * + *

Short

+ */ + .o-tooltip--left { + position: relative; + } + + .o-tooltip--left:after { + opacity: 0; + visibility: hidden; + position: absolute; + content: attr(data-tooltip); + padding: .2em; + font-size: .8em; + left: -.2em; + background: grey; + color: white; + white-space: nowrap; + z-index: 2; + border-radius: 2px; + transform: translateX(-102%) translateY(0); + transition: opacity 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1); +} + +.o-tooltip--left:hover:after { + display: block; + opacity: 1; + visibility: visible; + transform: translateX(-100%) translateY(0); + transition: opacity 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1); + transition-delay: .5s; +} + +/* By default the copy button shouldn't show up when printing a page */ +@media print { + button.copybtn { + display: none; + } +} diff --git a/_static/copybutton.js b/_static/copybutton.js new file mode 100644 index 0000000..2ea7ff3 --- /dev/null +++ b/_static/copybutton.js @@ -0,0 +1,248 @@ +// Localization support +const messages = { + 'en': { + 'copy': 'Copy', + 'copy_to_clipboard': 'Copy to clipboard', + 'copy_success': 'Copied!', + 'copy_failure': 'Failed to copy', + }, + 'es' : { + 'copy': 'Copiar', + 'copy_to_clipboard': 'Copiar al portapapeles', + 'copy_success': '¡Copiado!', + 'copy_failure': 'Error al copiar', + }, + 'de' : { + 'copy': 'Kopieren', + 'copy_to_clipboard': 'In die Zwischenablage kopieren', + 'copy_success': 'Kopiert!', + 'copy_failure': 'Fehler beim Kopieren', + }, + 'fr' : { + 'copy': 'Copier', + 'copy_to_clipboard': 'Copier dans le presse-papier', + 'copy_success': 'Copié !', + 'copy_failure': 'Échec de la copie', + }, + 'ru': { + 'copy': 'Скопировать', + 'copy_to_clipboard': 'Скопировать в буфер', + 'copy_success': 'Скопировано!', + 'copy_failure': 'Не удалось скопировать', + }, + 'zh-CN': { + 'copy': '复制', + 'copy_to_clipboard': '复制到剪贴板', + 'copy_success': '复制成功!', + 'copy_failure': '复制失败', + }, + 'it' : { + 'copy': 'Copiare', + 'copy_to_clipboard': 'Copiato negli appunti', + 'copy_success': 'Copiato!', + 'copy_failure': 'Errore durante la copia', + } +} + +let locale = 'en' +if( document.documentElement.lang !== undefined + && messages[document.documentElement.lang] !== undefined ) { + locale = document.documentElement.lang +} + +let doc_url_root = DOCUMENTATION_OPTIONS.URL_ROOT; +if (doc_url_root == '#') { + doc_url_root = ''; +} + +/** + * SVG files for our copy buttons + */ +let iconCheck = ` + ${messages[locale]['copy_success']} + + +` + +// If the user specified their own SVG use that, otherwise use the default +let iconCopy = ``; +if (!iconCopy) { + iconCopy = ` + ${messages[locale]['copy_to_clipboard']} + + + +` +} + +/** + * Set up copy/paste for code blocks + */ + +const runWhenDOMLoaded = cb => { + if (document.readyState != 'loading') { + cb() + } else if (document.addEventListener) { + document.addEventListener('DOMContentLoaded', cb) + } else { + document.attachEvent('onreadystatechange', function() { + if (document.readyState == 'complete') cb() + }) + } +} + +const codeCellId = index => `codecell${index}` + +// Clears selected text since ClipboardJS will select the text when copying +const clearSelection = () => { + if (window.getSelection) { + window.getSelection().removeAllRanges() + } else if (document.selection) { + document.selection.empty() + } +} + +// Changes tooltip text for a moment, then changes it back +// We want the timeout of our `success` class to be a bit shorter than the +// tooltip and icon change, so that we can hide the icon before changing back. +var timeoutIcon = 2000; +var timeoutSuccessClass = 1500; + +const temporarilyChangeTooltip = (el, oldText, newText) => { + el.setAttribute('data-tooltip', newText) + el.classList.add('success') + // Remove success a little bit sooner than we change the tooltip + // So that we can use CSS to hide the copybutton first + setTimeout(() => el.classList.remove('success'), timeoutSuccessClass) + setTimeout(() => el.setAttribute('data-tooltip', oldText), timeoutIcon) +} + +// Changes the copy button icon for two seconds, then changes it back +const temporarilyChangeIcon = (el) => { + el.innerHTML = iconCheck; + setTimeout(() => {el.innerHTML = iconCopy}, timeoutIcon) +} + +const addCopyButtonToCodeCells = () => { + // If ClipboardJS hasn't loaded, wait a bit and try again. This + // happens because we load ClipboardJS asynchronously. + if (window.ClipboardJS === undefined) { + setTimeout(addCopyButtonToCodeCells, 250) + return + } + + // Add copybuttons to all of our code cells + const COPYBUTTON_SELECTOR = 'div.highlight pre'; + const codeCells = document.querySelectorAll(COPYBUTTON_SELECTOR) + codeCells.forEach((codeCell, index) => { + const id = codeCellId(index) + codeCell.setAttribute('id', id) + + const clipboardButton = id => + `` + codeCell.insertAdjacentHTML('afterend', clipboardButton(id)) + }) + +function escapeRegExp(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string +} + +/** + * Removes excluded text from a Node. + * + * @param {Node} target Node to filter. + * @param {string} exclude CSS selector of nodes to exclude. + * @returns {DOMString} Text from `target` with text removed. + */ +function filterText(target, exclude) { + const clone = target.cloneNode(true); // clone as to not modify the live DOM + if (exclude) { + // remove excluded nodes + clone.querySelectorAll(exclude).forEach(node => node.remove()); + } + return clone.innerText; +} + +// Callback when a copy button is clicked. Will be passed the node that was clicked +// should then grab the text and replace pieces of text that shouldn't be used in output +function formatCopyText(textContent, copybuttonPromptText, isRegexp = false, onlyCopyPromptLines = true, removePrompts = true, copyEmptyLines = true, lineContinuationChar = "", hereDocDelim = "") { + var regexp; + var match; + + // Do we check for line continuation characters and "HERE-documents"? + var useLineCont = !!lineContinuationChar + var useHereDoc = !!hereDocDelim + + // create regexp to capture prompt and remaining line + if (isRegexp) { + regexp = new RegExp('^(' + copybuttonPromptText + ')(.*)') + } else { + regexp = new RegExp('^(' + escapeRegExp(copybuttonPromptText) + ')(.*)') + } + + const outputLines = []; + var promptFound = false; + var gotLineCont = false; + var gotHereDoc = false; + const lineGotPrompt = []; + for (const line of textContent.split('\n')) { + match = line.match(regexp) + if (match || gotLineCont || gotHereDoc) { + promptFound = regexp.test(line) + lineGotPrompt.push(promptFound) + if (removePrompts && promptFound) { + outputLines.push(match[2]) + } else { + outputLines.push(line) + } + gotLineCont = line.endsWith(lineContinuationChar) & useLineCont + if (line.includes(hereDocDelim) & useHereDoc) + gotHereDoc = !gotHereDoc + } else if (!onlyCopyPromptLines) { + outputLines.push(line) + } else if (copyEmptyLines && line.trim() === '') { + outputLines.push(line) + } + } + + // If no lines with the prompt were found then just use original lines + if (lineGotPrompt.some(v => v === true)) { + textContent = outputLines.join('\n'); + } + + // Remove a trailing newline to avoid auto-running when pasting + if (textContent.endsWith("\n")) { + textContent = textContent.slice(0, -1) + } + return textContent +} + + +var copyTargetText = (trigger) => { + var target = document.querySelector(trigger.attributes['data-clipboard-target'].value); + + // get filtered text + let exclude = '.linenos'; + + let text = filterText(target, exclude); + return formatCopyText(text, '', false, true, true, true, '', '') +} + + // Initialize with a callback so we can modify the text before copy + const clipboard = new ClipboardJS('.copybtn', {text: copyTargetText}) + + // Update UI with error/success messages + clipboard.on('success', event => { + clearSelection() + temporarilyChangeTooltip(event.trigger, messages[locale]['copy'], messages[locale]['copy_success']) + temporarilyChangeIcon(event.trigger) + }) + + clipboard.on('error', event => { + temporarilyChangeTooltip(event.trigger, messages[locale]['copy'], messages[locale]['copy_failure']) + }) +} + +runWhenDOMLoaded(addCopyButtonToCodeCells) \ No newline at end of file diff --git a/_static/copybutton_funcs.js b/_static/copybutton_funcs.js new file mode 100644 index 0000000..dbe1aaa --- /dev/null +++ b/_static/copybutton_funcs.js @@ -0,0 +1,73 @@ +function escapeRegExp(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string +} + +/** + * Removes excluded text from a Node. + * + * @param {Node} target Node to filter. + * @param {string} exclude CSS selector of nodes to exclude. + * @returns {DOMString} Text from `target` with text removed. + */ +export function filterText(target, exclude) { + const clone = target.cloneNode(true); // clone as to not modify the live DOM + if (exclude) { + // remove excluded nodes + clone.querySelectorAll(exclude).forEach(node => node.remove()); + } + return clone.innerText; +} + +// Callback when a copy button is clicked. Will be passed the node that was clicked +// should then grab the text and replace pieces of text that shouldn't be used in output +export function formatCopyText(textContent, copybuttonPromptText, isRegexp = false, onlyCopyPromptLines = true, removePrompts = true, copyEmptyLines = true, lineContinuationChar = "", hereDocDelim = "") { + var regexp; + var match; + + // Do we check for line continuation characters and "HERE-documents"? + var useLineCont = !!lineContinuationChar + var useHereDoc = !!hereDocDelim + + // create regexp to capture prompt and remaining line + if (isRegexp) { + regexp = new RegExp('^(' + copybuttonPromptText + ')(.*)') + } else { + regexp = new RegExp('^(' + escapeRegExp(copybuttonPromptText) + ')(.*)') + } + + const outputLines = []; + var promptFound = false; + var gotLineCont = false; + var gotHereDoc = false; + const lineGotPrompt = []; + for (const line of textContent.split('\n')) { + match = line.match(regexp) + if (match || gotLineCont || gotHereDoc) { + promptFound = regexp.test(line) + lineGotPrompt.push(promptFound) + if (removePrompts && promptFound) { + outputLines.push(match[2]) + } else { + outputLines.push(line) + } + gotLineCont = line.endsWith(lineContinuationChar) & useLineCont + if (line.includes(hereDocDelim) & useHereDoc) + gotHereDoc = !gotHereDoc + } else if (!onlyCopyPromptLines) { + outputLines.push(line) + } else if (copyEmptyLines && line.trim() === '') { + outputLines.push(line) + } + } + + // If no lines with the prompt were found then just use original lines + if (lineGotPrompt.some(v => v === true)) { + textContent = outputLines.join('\n'); + } + + // Remove a trailing newline to avoid auto-running when pasting + if (textContent.endsWith("\n")) { + textContent = textContent.slice(0, -1) + } + return textContent +} diff --git a/_static/dataframe.css b/_static/dataframe.css new file mode 100644 index 0000000..8076a48 --- /dev/null +++ b/_static/dataframe.css @@ -0,0 +1,49 @@ +table.dataframe { + margin-left: auto; + margin-right: auto; + border: none; + border-collapse: collapse; + border-spacing: 0; + font-size: 12px; + table-layout: auto; + width: 100%; +} + +.dataframe tr, +.dataframe th, +.dataframe td { + text-align: right; + vertical-align: middle; + padding: 0.5em 0.5em; + line-height: normal; + white-space: normal; + max-width: none; + border: none; +} + +.dataframe tbody { + display: table-row-group; + vertical-align: middle; + border-color: inherit; +} + +.dataframe tbody tr:nth-child(odd) { + background-color: var(--pst-color-surface, #f5f5f5); + color: var(--pst-color-text-base); +} + +.dataframe thead { + border-bottom: 1px solid var(--pst-color-border); + vertical-align: bottom; +} + +.dataframe tbody tr:hover { + background-color: #e1f5fe; + color: #000000; + cursor: pointer; +} + +:host { + overflow: auto; + padding-right: 1px; +} diff --git a/_static/design-style.1e8bd061cd6da7fc9cf755528e8ffc24.min.css b/_static/design-style.1e8bd061cd6da7fc9cf755528e8ffc24.min.css new file mode 100644 index 0000000..eb19f69 --- /dev/null +++ b/_static/design-style.1e8bd061cd6da7fc9cf755528e8ffc24.min.css @@ -0,0 +1 @@ +.sd-bg-primary{background-color:var(--sd-color-primary) !important}.sd-bg-text-primary{color:var(--sd-color-primary-text) !important}button.sd-bg-primary:focus,button.sd-bg-primary:hover{background-color:var(--sd-color-primary-highlight) !important}a.sd-bg-primary:focus,a.sd-bg-primary:hover{background-color:var(--sd-color-primary-highlight) !important}.sd-bg-secondary{background-color:var(--sd-color-secondary) !important}.sd-bg-text-secondary{color:var(--sd-color-secondary-text) !important}button.sd-bg-secondary:focus,button.sd-bg-secondary:hover{background-color:var(--sd-color-secondary-highlight) !important}a.sd-bg-secondary:focus,a.sd-bg-secondary:hover{background-color:var(--sd-color-secondary-highlight) !important}.sd-bg-success{background-color:var(--sd-color-success) !important}.sd-bg-text-success{color:var(--sd-color-success-text) !important}button.sd-bg-success:focus,button.sd-bg-success:hover{background-color:var(--sd-color-success-highlight) !important}a.sd-bg-success:focus,a.sd-bg-success:hover{background-color:var(--sd-color-success-highlight) !important}.sd-bg-info{background-color:var(--sd-color-info) !important}.sd-bg-text-info{color:var(--sd-color-info-text) !important}button.sd-bg-info:focus,button.sd-bg-info:hover{background-color:var(--sd-color-info-highlight) !important}a.sd-bg-info:focus,a.sd-bg-info:hover{background-color:var(--sd-color-info-highlight) !important}.sd-bg-warning{background-color:var(--sd-color-warning) !important}.sd-bg-text-warning{color:var(--sd-color-warning-text) !important}button.sd-bg-warning:focus,button.sd-bg-warning:hover{background-color:var(--sd-color-warning-highlight) !important}a.sd-bg-warning:focus,a.sd-bg-warning:hover{background-color:var(--sd-color-warning-highlight) !important}.sd-bg-danger{background-color:var(--sd-color-danger) !important}.sd-bg-text-danger{color:var(--sd-color-danger-text) !important}button.sd-bg-danger:focus,button.sd-bg-danger:hover{background-color:var(--sd-color-danger-highlight) !important}a.sd-bg-danger:focus,a.sd-bg-danger:hover{background-color:var(--sd-color-danger-highlight) !important}.sd-bg-light{background-color:var(--sd-color-light) !important}.sd-bg-text-light{color:var(--sd-color-light-text) !important}button.sd-bg-light:focus,button.sd-bg-light:hover{background-color:var(--sd-color-light-highlight) !important}a.sd-bg-light:focus,a.sd-bg-light:hover{background-color:var(--sd-color-light-highlight) !important}.sd-bg-muted{background-color:var(--sd-color-muted) !important}.sd-bg-text-muted{color:var(--sd-color-muted-text) !important}button.sd-bg-muted:focus,button.sd-bg-muted:hover{background-color:var(--sd-color-muted-highlight) !important}a.sd-bg-muted:focus,a.sd-bg-muted:hover{background-color:var(--sd-color-muted-highlight) !important}.sd-bg-dark{background-color:var(--sd-color-dark) !important}.sd-bg-text-dark{color:var(--sd-color-dark-text) !important}button.sd-bg-dark:focus,button.sd-bg-dark:hover{background-color:var(--sd-color-dark-highlight) !important}a.sd-bg-dark:focus,a.sd-bg-dark:hover{background-color:var(--sd-color-dark-highlight) !important}.sd-bg-black{background-color:var(--sd-color-black) !important}.sd-bg-text-black{color:var(--sd-color-black-text) !important}button.sd-bg-black:focus,button.sd-bg-black:hover{background-color:var(--sd-color-black-highlight) !important}a.sd-bg-black:focus,a.sd-bg-black:hover{background-color:var(--sd-color-black-highlight) !important}.sd-bg-white{background-color:var(--sd-color-white) !important}.sd-bg-text-white{color:var(--sd-color-white-text) !important}button.sd-bg-white:focus,button.sd-bg-white:hover{background-color:var(--sd-color-white-highlight) !important}a.sd-bg-white:focus,a.sd-bg-white:hover{background-color:var(--sd-color-white-highlight) !important}.sd-text-primary,.sd-text-primary>p{color:var(--sd-color-primary) !important}a.sd-text-primary:focus,a.sd-text-primary:hover{color:var(--sd-color-primary-highlight) !important}.sd-text-secondary,.sd-text-secondary>p{color:var(--sd-color-secondary) !important}a.sd-text-secondary:focus,a.sd-text-secondary:hover{color:var(--sd-color-secondary-highlight) !important}.sd-text-success,.sd-text-success>p{color:var(--sd-color-success) !important}a.sd-text-success:focus,a.sd-text-success:hover{color:var(--sd-color-success-highlight) !important}.sd-text-info,.sd-text-info>p{color:var(--sd-color-info) !important}a.sd-text-info:focus,a.sd-text-info:hover{color:var(--sd-color-info-highlight) !important}.sd-text-warning,.sd-text-warning>p{color:var(--sd-color-warning) !important}a.sd-text-warning:focus,a.sd-text-warning:hover{color:var(--sd-color-warning-highlight) !important}.sd-text-danger,.sd-text-danger>p{color:var(--sd-color-danger) !important}a.sd-text-danger:focus,a.sd-text-danger:hover{color:var(--sd-color-danger-highlight) !important}.sd-text-light,.sd-text-light>p{color:var(--sd-color-light) !important}a.sd-text-light:focus,a.sd-text-light:hover{color:var(--sd-color-light-highlight) !important}.sd-text-muted,.sd-text-muted>p{color:var(--sd-color-muted) !important}a.sd-text-muted:focus,a.sd-text-muted:hover{color:var(--sd-color-muted-highlight) !important}.sd-text-dark,.sd-text-dark>p{color:var(--sd-color-dark) !important}a.sd-text-dark:focus,a.sd-text-dark:hover{color:var(--sd-color-dark-highlight) !important}.sd-text-black,.sd-text-black>p{color:var(--sd-color-black) !important}a.sd-text-black:focus,a.sd-text-black:hover{color:var(--sd-color-black-highlight) !important}.sd-text-white,.sd-text-white>p{color:var(--sd-color-white) !important}a.sd-text-white:focus,a.sd-text-white:hover{color:var(--sd-color-white-highlight) !important}.sd-outline-primary{border-color:var(--sd-color-primary) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-primary:focus,a.sd-outline-primary:hover{border-color:var(--sd-color-primary-highlight) !important}.sd-outline-secondary{border-color:var(--sd-color-secondary) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-secondary:focus,a.sd-outline-secondary:hover{border-color:var(--sd-color-secondary-highlight) !important}.sd-outline-success{border-color:var(--sd-color-success) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-success:focus,a.sd-outline-success:hover{border-color:var(--sd-color-success-highlight) !important}.sd-outline-info{border-color:var(--sd-color-info) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-info:focus,a.sd-outline-info:hover{border-color:var(--sd-color-info-highlight) !important}.sd-outline-warning{border-color:var(--sd-color-warning) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-warning:focus,a.sd-outline-warning:hover{border-color:var(--sd-color-warning-highlight) !important}.sd-outline-danger{border-color:var(--sd-color-danger) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-danger:focus,a.sd-outline-danger:hover{border-color:var(--sd-color-danger-highlight) !important}.sd-outline-light{border-color:var(--sd-color-light) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-light:focus,a.sd-outline-light:hover{border-color:var(--sd-color-light-highlight) !important}.sd-outline-muted{border-color:var(--sd-color-muted) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-muted:focus,a.sd-outline-muted:hover{border-color:var(--sd-color-muted-highlight) !important}.sd-outline-dark{border-color:var(--sd-color-dark) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-dark:focus,a.sd-outline-dark:hover{border-color:var(--sd-color-dark-highlight) !important}.sd-outline-black{border-color:var(--sd-color-black) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-black:focus,a.sd-outline-black:hover{border-color:var(--sd-color-black-highlight) !important}.sd-outline-white{border-color:var(--sd-color-white) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-white:focus,a.sd-outline-white:hover{border-color:var(--sd-color-white-highlight) !important}.sd-bg-transparent{background-color:transparent !important}.sd-outline-transparent{border-color:transparent !important}.sd-text-transparent{color:transparent !important}.sd-p-0{padding:0 !important}.sd-pt-0,.sd-py-0{padding-top:0 !important}.sd-pr-0,.sd-px-0{padding-right:0 !important}.sd-pb-0,.sd-py-0{padding-bottom:0 !important}.sd-pl-0,.sd-px-0{padding-left:0 !important}.sd-p-1{padding:.25rem !important}.sd-pt-1,.sd-py-1{padding-top:.25rem !important}.sd-pr-1,.sd-px-1{padding-right:.25rem !important}.sd-pb-1,.sd-py-1{padding-bottom:.25rem !important}.sd-pl-1,.sd-px-1{padding-left:.25rem !important}.sd-p-2{padding:.5rem !important}.sd-pt-2,.sd-py-2{padding-top:.5rem !important}.sd-pr-2,.sd-px-2{padding-right:.5rem !important}.sd-pb-2,.sd-py-2{padding-bottom:.5rem !important}.sd-pl-2,.sd-px-2{padding-left:.5rem !important}.sd-p-3{padding:1rem !important}.sd-pt-3,.sd-py-3{padding-top:1rem !important}.sd-pr-3,.sd-px-3{padding-right:1rem !important}.sd-pb-3,.sd-py-3{padding-bottom:1rem !important}.sd-pl-3,.sd-px-3{padding-left:1rem !important}.sd-p-4{padding:1.5rem !important}.sd-pt-4,.sd-py-4{padding-top:1.5rem !important}.sd-pr-4,.sd-px-4{padding-right:1.5rem !important}.sd-pb-4,.sd-py-4{padding-bottom:1.5rem !important}.sd-pl-4,.sd-px-4{padding-left:1.5rem !important}.sd-p-5{padding:3rem !important}.sd-pt-5,.sd-py-5{padding-top:3rem !important}.sd-pr-5,.sd-px-5{padding-right:3rem !important}.sd-pb-5,.sd-py-5{padding-bottom:3rem !important}.sd-pl-5,.sd-px-5{padding-left:3rem !important}.sd-m-auto{margin:auto !important}.sd-mt-auto,.sd-my-auto{margin-top:auto !important}.sd-mr-auto,.sd-mx-auto{margin-right:auto !important}.sd-mb-auto,.sd-my-auto{margin-bottom:auto !important}.sd-ml-auto,.sd-mx-auto{margin-left:auto !important}.sd-m-0{margin:0 !important}.sd-mt-0,.sd-my-0{margin-top:0 !important}.sd-mr-0,.sd-mx-0{margin-right:0 !important}.sd-mb-0,.sd-my-0{margin-bottom:0 !important}.sd-ml-0,.sd-mx-0{margin-left:0 !important}.sd-m-1{margin:.25rem !important}.sd-mt-1,.sd-my-1{margin-top:.25rem !important}.sd-mr-1,.sd-mx-1{margin-right:.25rem !important}.sd-mb-1,.sd-my-1{margin-bottom:.25rem !important}.sd-ml-1,.sd-mx-1{margin-left:.25rem !important}.sd-m-2{margin:.5rem !important}.sd-mt-2,.sd-my-2{margin-top:.5rem !important}.sd-mr-2,.sd-mx-2{margin-right:.5rem !important}.sd-mb-2,.sd-my-2{margin-bottom:.5rem !important}.sd-ml-2,.sd-mx-2{margin-left:.5rem !important}.sd-m-3{margin:1rem !important}.sd-mt-3,.sd-my-3{margin-top:1rem !important}.sd-mr-3,.sd-mx-3{margin-right:1rem !important}.sd-mb-3,.sd-my-3{margin-bottom:1rem !important}.sd-ml-3,.sd-mx-3{margin-left:1rem !important}.sd-m-4{margin:1.5rem !important}.sd-mt-4,.sd-my-4{margin-top:1.5rem !important}.sd-mr-4,.sd-mx-4{margin-right:1.5rem !important}.sd-mb-4,.sd-my-4{margin-bottom:1.5rem !important}.sd-ml-4,.sd-mx-4{margin-left:1.5rem !important}.sd-m-5{margin:3rem !important}.sd-mt-5,.sd-my-5{margin-top:3rem !important}.sd-mr-5,.sd-mx-5{margin-right:3rem !important}.sd-mb-5,.sd-my-5{margin-bottom:3rem !important}.sd-ml-5,.sd-mx-5{margin-left:3rem !important}.sd-w-25{width:25% !important}.sd-w-50{width:50% !important}.sd-w-75{width:75% !important}.sd-w-100{width:100% !important}.sd-w-auto{width:auto !important}.sd-h-25{height:25% !important}.sd-h-50{height:50% !important}.sd-h-75{height:75% !important}.sd-h-100{height:100% !important}.sd-h-auto{height:auto !important}.sd-d-none{display:none !important}.sd-d-inline{display:inline !important}.sd-d-inline-block{display:inline-block !important}.sd-d-block{display:block !important}.sd-d-grid{display:grid !important}.sd-d-flex-row{display:-ms-flexbox !important;display:flex !important;flex-direction:row !important}.sd-d-flex-column{display:-ms-flexbox !important;display:flex !important;flex-direction:column !important}.sd-d-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}@media(min-width: 576px){.sd-d-sm-none{display:none !important}.sd-d-sm-inline{display:inline !important}.sd-d-sm-inline-block{display:inline-block !important}.sd-d-sm-block{display:block !important}.sd-d-sm-grid{display:grid !important}.sd-d-sm-flex{display:-ms-flexbox !important;display:flex !important}.sd-d-sm-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}}@media(min-width: 768px){.sd-d-md-none{display:none !important}.sd-d-md-inline{display:inline !important}.sd-d-md-inline-block{display:inline-block !important}.sd-d-md-block{display:block !important}.sd-d-md-grid{display:grid !important}.sd-d-md-flex{display:-ms-flexbox !important;display:flex !important}.sd-d-md-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}}@media(min-width: 992px){.sd-d-lg-none{display:none !important}.sd-d-lg-inline{display:inline !important}.sd-d-lg-inline-block{display:inline-block !important}.sd-d-lg-block{display:block !important}.sd-d-lg-grid{display:grid !important}.sd-d-lg-flex{display:-ms-flexbox !important;display:flex !important}.sd-d-lg-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}}@media(min-width: 1200px){.sd-d-xl-none{display:none !important}.sd-d-xl-inline{display:inline !important}.sd-d-xl-inline-block{display:inline-block !important}.sd-d-xl-block{display:block !important}.sd-d-xl-grid{display:grid !important}.sd-d-xl-flex{display:-ms-flexbox !important;display:flex !important}.sd-d-xl-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}}.sd-align-major-start{justify-content:flex-start !important}.sd-align-major-end{justify-content:flex-end !important}.sd-align-major-center{justify-content:center !important}.sd-align-major-justify{justify-content:space-between !important}.sd-align-major-spaced{justify-content:space-evenly !important}.sd-align-minor-start{align-items:flex-start !important}.sd-align-minor-end{align-items:flex-end !important}.sd-align-minor-center{align-items:center !important}.sd-align-minor-stretch{align-items:stretch !important}.sd-text-justify{text-align:justify !important}.sd-text-left{text-align:left !important}.sd-text-right{text-align:right !important}.sd-text-center{text-align:center !important}.sd-font-weight-light{font-weight:300 !important}.sd-font-weight-lighter{font-weight:lighter !important}.sd-font-weight-normal{font-weight:400 !important}.sd-font-weight-bold{font-weight:700 !important}.sd-font-weight-bolder{font-weight:bolder !important}.sd-font-italic{font-style:italic !important}.sd-text-decoration-none{text-decoration:none !important}.sd-text-lowercase{text-transform:lowercase !important}.sd-text-uppercase{text-transform:uppercase !important}.sd-text-capitalize{text-transform:capitalize !important}.sd-text-wrap{white-space:normal !important}.sd-text-nowrap{white-space:nowrap !important}.sd-text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sd-fs-1,.sd-fs-1>p{font-size:calc(1.375rem + 1.5vw) !important;line-height:unset !important}.sd-fs-2,.sd-fs-2>p{font-size:calc(1.325rem + 0.9vw) !important;line-height:unset !important}.sd-fs-3,.sd-fs-3>p{font-size:calc(1.3rem + 0.6vw) !important;line-height:unset !important}.sd-fs-4,.sd-fs-4>p{font-size:calc(1.275rem + 0.3vw) !important;line-height:unset !important}.sd-fs-5,.sd-fs-5>p{font-size:1.25rem !important;line-height:unset !important}.sd-fs-6,.sd-fs-6>p{font-size:1rem !important;line-height:unset !important}.sd-border-0{border:0 solid !important}.sd-border-top-0{border-top:0 solid !important}.sd-border-bottom-0{border-bottom:0 solid !important}.sd-border-right-0{border-right:0 solid !important}.sd-border-left-0{border-left:0 solid !important}.sd-border-1{border:1px solid !important}.sd-border-top-1{border-top:1px solid !important}.sd-border-bottom-1{border-bottom:1px solid !important}.sd-border-right-1{border-right:1px solid !important}.sd-border-left-1{border-left:1px solid !important}.sd-border-2{border:2px solid !important}.sd-border-top-2{border-top:2px solid !important}.sd-border-bottom-2{border-bottom:2px solid !important}.sd-border-right-2{border-right:2px solid !important}.sd-border-left-2{border-left:2px solid !important}.sd-border-3{border:3px solid !important}.sd-border-top-3{border-top:3px solid !important}.sd-border-bottom-3{border-bottom:3px solid !important}.sd-border-right-3{border-right:3px solid !important}.sd-border-left-3{border-left:3px solid !important}.sd-border-4{border:4px solid !important}.sd-border-top-4{border-top:4px solid !important}.sd-border-bottom-4{border-bottom:4px solid !important}.sd-border-right-4{border-right:4px solid !important}.sd-border-left-4{border-left:4px solid !important}.sd-border-5{border:5px solid !important}.sd-border-top-5{border-top:5px solid !important}.sd-border-bottom-5{border-bottom:5px solid !important}.sd-border-right-5{border-right:5px solid !important}.sd-border-left-5{border-left:5px solid !important}.sd-rounded-0{border-radius:0 !important}.sd-rounded-1{border-radius:.2rem !important}.sd-rounded-2{border-radius:.3rem !important}.sd-rounded-3{border-radius:.5rem !important}.sd-rounded-pill{border-radius:50rem !important}.sd-rounded-circle{border-radius:50% !important}.shadow-none{box-shadow:none !important}.sd-shadow-sm{box-shadow:0 .125rem .25rem var(--sd-color-shadow) !important}.sd-shadow-md{box-shadow:0 .5rem 1rem var(--sd-color-shadow) !important}.sd-shadow-lg{box-shadow:0 1rem 3rem var(--sd-color-shadow) !important}@keyframes sd-slide-from-left{0%{transform:translateX(-100%)}100%{transform:translateX(0)}}@keyframes sd-slide-from-right{0%{transform:translateX(200%)}100%{transform:translateX(0)}}@keyframes sd-grow100{0%{transform:scale(0);opacity:.5}100%{transform:scale(1);opacity:1}}@keyframes sd-grow50{0%{transform:scale(0.5);opacity:.5}100%{transform:scale(1);opacity:1}}@keyframes sd-grow50-rot20{0%{transform:scale(0.5) rotateZ(-20deg);opacity:.5}75%{transform:scale(1) rotateZ(5deg);opacity:1}95%{transform:scale(1) rotateZ(-1deg);opacity:1}100%{transform:scale(1) rotateZ(0);opacity:1}}.sd-animate-slide-from-left{animation:1s ease-out 0s 1 normal none running sd-slide-from-left}.sd-animate-slide-from-right{animation:1s ease-out 0s 1 normal none running sd-slide-from-right}.sd-animate-grow100{animation:1s ease-out 0s 1 normal none running sd-grow100}.sd-animate-grow50{animation:1s ease-out 0s 1 normal none running sd-grow50}.sd-animate-grow50-rot20{animation:1s ease-out 0s 1 normal none running sd-grow50-rot20}.sd-badge{display:inline-block;padding:.35em .65em;font-size:.75em;font-weight:700;line-height:1;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25rem}.sd-badge:empty{display:none}a.sd-badge{text-decoration:none}.sd-btn .sd-badge{position:relative;top:-1px}.sd-btn{background-color:transparent;border:1px solid transparent;border-radius:.25rem;cursor:pointer;display:inline-block;font-weight:400;font-size:1rem;line-height:1.5;padding:.375rem .75rem;text-align:center;text-decoration:none;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;vertical-align:middle;user-select:none;-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none}.sd-btn:hover{text-decoration:none}@media(prefers-reduced-motion: reduce){.sd-btn{transition:none}}.sd-btn-primary,.sd-btn-outline-primary:hover,.sd-btn-outline-primary:focus{color:var(--sd-color-primary-text) !important;background-color:var(--sd-color-primary) !important;border-color:var(--sd-color-primary) !important;border-width:1px !important;border-style:solid !important}.sd-btn-primary:hover,.sd-btn-primary:focus{color:var(--sd-color-primary-text) !important;background-color:var(--sd-color-primary-highlight) !important;border-color:var(--sd-color-primary-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-primary{color:var(--sd-color-primary) !important;border-color:var(--sd-color-primary) !important;border-width:1px !important;border-style:solid !important}.sd-btn-secondary,.sd-btn-outline-secondary:hover,.sd-btn-outline-secondary:focus{color:var(--sd-color-secondary-text) !important;background-color:var(--sd-color-secondary) !important;border-color:var(--sd-color-secondary) !important;border-width:1px !important;border-style:solid !important}.sd-btn-secondary:hover,.sd-btn-secondary:focus{color:var(--sd-color-secondary-text) !important;background-color:var(--sd-color-secondary-highlight) !important;border-color:var(--sd-color-secondary-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-secondary{color:var(--sd-color-secondary) !important;border-color:var(--sd-color-secondary) !important;border-width:1px !important;border-style:solid !important}.sd-btn-success,.sd-btn-outline-success:hover,.sd-btn-outline-success:focus{color:var(--sd-color-success-text) !important;background-color:var(--sd-color-success) !important;border-color:var(--sd-color-success) !important;border-width:1px !important;border-style:solid !important}.sd-btn-success:hover,.sd-btn-success:focus{color:var(--sd-color-success-text) !important;background-color:var(--sd-color-success-highlight) !important;border-color:var(--sd-color-success-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-success{color:var(--sd-color-success) !important;border-color:var(--sd-color-success) !important;border-width:1px !important;border-style:solid !important}.sd-btn-info,.sd-btn-outline-info:hover,.sd-btn-outline-info:focus{color:var(--sd-color-info-text) !important;background-color:var(--sd-color-info) !important;border-color:var(--sd-color-info) !important;border-width:1px !important;border-style:solid !important}.sd-btn-info:hover,.sd-btn-info:focus{color:var(--sd-color-info-text) !important;background-color:var(--sd-color-info-highlight) !important;border-color:var(--sd-color-info-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-info{color:var(--sd-color-info) !important;border-color:var(--sd-color-info) !important;border-width:1px !important;border-style:solid !important}.sd-btn-warning,.sd-btn-outline-warning:hover,.sd-btn-outline-warning:focus{color:var(--sd-color-warning-text) !important;background-color:var(--sd-color-warning) !important;border-color:var(--sd-color-warning) !important;border-width:1px !important;border-style:solid !important}.sd-btn-warning:hover,.sd-btn-warning:focus{color:var(--sd-color-warning-text) !important;background-color:var(--sd-color-warning-highlight) !important;border-color:var(--sd-color-warning-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-warning{color:var(--sd-color-warning) !important;border-color:var(--sd-color-warning) !important;border-width:1px !important;border-style:solid !important}.sd-btn-danger,.sd-btn-outline-danger:hover,.sd-btn-outline-danger:focus{color:var(--sd-color-danger-text) !important;background-color:var(--sd-color-danger) !important;border-color:var(--sd-color-danger) !important;border-width:1px !important;border-style:solid !important}.sd-btn-danger:hover,.sd-btn-danger:focus{color:var(--sd-color-danger-text) !important;background-color:var(--sd-color-danger-highlight) !important;border-color:var(--sd-color-danger-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-danger{color:var(--sd-color-danger) !important;border-color:var(--sd-color-danger) !important;border-width:1px !important;border-style:solid !important}.sd-btn-light,.sd-btn-outline-light:hover,.sd-btn-outline-light:focus{color:var(--sd-color-light-text) !important;background-color:var(--sd-color-light) !important;border-color:var(--sd-color-light) !important;border-width:1px !important;border-style:solid !important}.sd-btn-light:hover,.sd-btn-light:focus{color:var(--sd-color-light-text) !important;background-color:var(--sd-color-light-highlight) !important;border-color:var(--sd-color-light-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-light{color:var(--sd-color-light) !important;border-color:var(--sd-color-light) !important;border-width:1px !important;border-style:solid !important}.sd-btn-muted,.sd-btn-outline-muted:hover,.sd-btn-outline-muted:focus{color:var(--sd-color-muted-text) !important;background-color:var(--sd-color-muted) !important;border-color:var(--sd-color-muted) !important;border-width:1px !important;border-style:solid !important}.sd-btn-muted:hover,.sd-btn-muted:focus{color:var(--sd-color-muted-text) !important;background-color:var(--sd-color-muted-highlight) !important;border-color:var(--sd-color-muted-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-muted{color:var(--sd-color-muted) !important;border-color:var(--sd-color-muted) !important;border-width:1px !important;border-style:solid !important}.sd-btn-dark,.sd-btn-outline-dark:hover,.sd-btn-outline-dark:focus{color:var(--sd-color-dark-text) !important;background-color:var(--sd-color-dark) !important;border-color:var(--sd-color-dark) !important;border-width:1px !important;border-style:solid !important}.sd-btn-dark:hover,.sd-btn-dark:focus{color:var(--sd-color-dark-text) !important;background-color:var(--sd-color-dark-highlight) !important;border-color:var(--sd-color-dark-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-dark{color:var(--sd-color-dark) !important;border-color:var(--sd-color-dark) !important;border-width:1px !important;border-style:solid !important}.sd-btn-black,.sd-btn-outline-black:hover,.sd-btn-outline-black:focus{color:var(--sd-color-black-text) !important;background-color:var(--sd-color-black) !important;border-color:var(--sd-color-black) !important;border-width:1px !important;border-style:solid !important}.sd-btn-black:hover,.sd-btn-black:focus{color:var(--sd-color-black-text) !important;background-color:var(--sd-color-black-highlight) !important;border-color:var(--sd-color-black-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-black{color:var(--sd-color-black) !important;border-color:var(--sd-color-black) !important;border-width:1px !important;border-style:solid !important}.sd-btn-white,.sd-btn-outline-white:hover,.sd-btn-outline-white:focus{color:var(--sd-color-white-text) !important;background-color:var(--sd-color-white) !important;border-color:var(--sd-color-white) !important;border-width:1px !important;border-style:solid !important}.sd-btn-white:hover,.sd-btn-white:focus{color:var(--sd-color-white-text) !important;background-color:var(--sd-color-white-highlight) !important;border-color:var(--sd-color-white-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-white{color:var(--sd-color-white) !important;border-color:var(--sd-color-white) !important;border-width:1px !important;border-style:solid !important}.sd-stretched-link::after{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;content:""}.sd-hide-link-text{font-size:0}.sd-octicon,.sd-material-icon{display:inline-block;fill:currentColor;vertical-align:middle}.sd-avatar-xs{border-radius:50%;object-fit:cover;object-position:center;width:1rem;height:1rem}.sd-avatar-sm{border-radius:50%;object-fit:cover;object-position:center;width:3rem;height:3rem}.sd-avatar-md{border-radius:50%;object-fit:cover;object-position:center;width:5rem;height:5rem}.sd-avatar-lg{border-radius:50%;object-fit:cover;object-position:center;width:7rem;height:7rem}.sd-avatar-xl{border-radius:50%;object-fit:cover;object-position:center;width:10rem;height:10rem}.sd-avatar-inherit{border-radius:50%;object-fit:cover;object-position:center;width:inherit;height:inherit}.sd-avatar-initial{border-radius:50%;object-fit:cover;object-position:center;width:initial;height:initial}.sd-card{background-clip:border-box;background-color:var(--sd-color-card-background);border:1px solid var(--sd-color-card-border);border-radius:.25rem;color:var(--sd-color-card-text);display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;min-width:0;position:relative;word-wrap:break-word}.sd-card>hr{margin-left:0;margin-right:0}.sd-card-hover:hover{border-color:var(--sd-color-card-border-hover);transform:scale(1.01)}.sd-card-body{-ms-flex:1 1 auto;flex:1 1 auto;padding:1rem 1rem}.sd-card-title{margin-bottom:.5rem}.sd-card-subtitle{margin-top:-0.25rem;margin-bottom:0}.sd-card-text:last-child{margin-bottom:0}.sd-card-link:hover{text-decoration:none}.sd-card-link+.card-link{margin-left:1rem}.sd-card-header{padding:.5rem 1rem;margin-bottom:0;background-color:var(--sd-color-card-header);border-bottom:1px solid var(--sd-color-card-border)}.sd-card-header:first-child{border-radius:calc(0.25rem - 1px) calc(0.25rem - 1px) 0 0}.sd-card-footer{padding:.5rem 1rem;background-color:var(--sd-color-card-footer);border-top:1px solid var(--sd-color-card-border)}.sd-card-footer:last-child{border-radius:0 0 calc(0.25rem - 1px) calc(0.25rem - 1px)}.sd-card-header-tabs{margin-right:-0.5rem;margin-bottom:-0.5rem;margin-left:-0.5rem;border-bottom:0}.sd-card-header-pills{margin-right:-0.5rem;margin-left:-0.5rem}.sd-card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1rem;border-radius:calc(0.25rem - 1px)}.sd-card-img,.sd-card-img-bottom,.sd-card-img-top{width:100%}.sd-card-img,.sd-card-img-top{border-top-left-radius:calc(0.25rem - 1px);border-top-right-radius:calc(0.25rem - 1px)}.sd-card-img,.sd-card-img-bottom{border-bottom-left-radius:calc(0.25rem - 1px);border-bottom-right-radius:calc(0.25rem - 1px)}.sd-cards-carousel{width:100%;display:flex;flex-wrap:nowrap;-ms-flex-direction:row;flex-direction:row;overflow-x:hidden;scroll-snap-type:x mandatory}.sd-cards-carousel.sd-show-scrollbar{overflow-x:auto}.sd-cards-carousel:hover,.sd-cards-carousel:focus{overflow-x:auto}.sd-cards-carousel>.sd-card{flex-shrink:0;scroll-snap-align:start}.sd-cards-carousel>.sd-card:not(:last-child){margin-right:3px}.sd-card-cols-1>.sd-card{width:90%}.sd-card-cols-2>.sd-card{width:45%}.sd-card-cols-3>.sd-card{width:30%}.sd-card-cols-4>.sd-card{width:22.5%}.sd-card-cols-5>.sd-card{width:18%}.sd-card-cols-6>.sd-card{width:15%}.sd-card-cols-7>.sd-card{width:12.8571428571%}.sd-card-cols-8>.sd-card{width:11.25%}.sd-card-cols-9>.sd-card{width:10%}.sd-card-cols-10>.sd-card{width:9%}.sd-card-cols-11>.sd-card{width:8.1818181818%}.sd-card-cols-12>.sd-card{width:7.5%}.sd-container,.sd-container-fluid,.sd-container-lg,.sd-container-md,.sd-container-sm,.sd-container-xl{margin-left:auto;margin-right:auto;padding-left:var(--sd-gutter-x, 0.75rem);padding-right:var(--sd-gutter-x, 0.75rem);width:100%}@media(min-width: 576px){.sd-container-sm,.sd-container{max-width:540px}}@media(min-width: 768px){.sd-container-md,.sd-container-sm,.sd-container{max-width:720px}}@media(min-width: 992px){.sd-container-lg,.sd-container-md,.sd-container-sm,.sd-container{max-width:960px}}@media(min-width: 1200px){.sd-container-xl,.sd-container-lg,.sd-container-md,.sd-container-sm,.sd-container{max-width:1140px}}.sd-row{--sd-gutter-x: 1.5rem;--sd-gutter-y: 0;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-top:calc(var(--sd-gutter-y) * -1);margin-right:calc(var(--sd-gutter-x) * -0.5);margin-left:calc(var(--sd-gutter-x) * -0.5)}.sd-row>*{box-sizing:border-box;flex-shrink:0;width:100%;max-width:100%;padding-right:calc(var(--sd-gutter-x) * 0.5);padding-left:calc(var(--sd-gutter-x) * 0.5);margin-top:var(--sd-gutter-y)}.sd-col{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-auto>*{flex:0 0 auto;width:auto}.sd-row-cols-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}@media(min-width: 576px){.sd-col-sm{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-sm-auto{flex:1 0 auto;-ms-flex:1 0 auto;width:100%}.sd-row-cols-sm-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-sm-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-sm-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-sm-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-sm-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-sm-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-sm-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-sm-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-sm-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-sm-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-sm-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-sm-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}}@media(min-width: 768px){.sd-col-md{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-md-auto{flex:1 0 auto;-ms-flex:1 0 auto;width:100%}.sd-row-cols-md-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-md-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-md-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-md-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-md-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-md-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-md-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-md-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-md-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-md-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-md-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-md-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}}@media(min-width: 992px){.sd-col-lg{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-lg-auto{flex:1 0 auto;-ms-flex:1 0 auto;width:100%}.sd-row-cols-lg-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-lg-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-lg-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-lg-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-lg-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-lg-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-lg-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-lg-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-lg-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-lg-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-lg-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-lg-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}}@media(min-width: 1200px){.sd-col-xl{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-xl-auto{flex:1 0 auto;-ms-flex:1 0 auto;width:100%}.sd-row-cols-xl-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-xl-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-xl-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-xl-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-xl-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-xl-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-xl-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-xl-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-xl-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-xl-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-xl-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-xl-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}}.sd-col-auto{flex:0 0 auto;-ms-flex:0 0 auto;width:auto}.sd-col-1{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}.sd-col-2{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-col-3{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-col-4{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-col-5{flex:0 0 auto;-ms-flex:0 0 auto;width:41.6666666667%}.sd-col-6{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-col-7{flex:0 0 auto;-ms-flex:0 0 auto;width:58.3333333333%}.sd-col-8{flex:0 0 auto;-ms-flex:0 0 auto;width:66.6666666667%}.sd-col-9{flex:0 0 auto;-ms-flex:0 0 auto;width:75%}.sd-col-10{flex:0 0 auto;-ms-flex:0 0 auto;width:83.3333333333%}.sd-col-11{flex:0 0 auto;-ms-flex:0 0 auto;width:91.6666666667%}.sd-col-12{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-g-0,.sd-gy-0{--sd-gutter-y: 0}.sd-g-0,.sd-gx-0{--sd-gutter-x: 0}.sd-g-1,.sd-gy-1{--sd-gutter-y: 0.25rem}.sd-g-1,.sd-gx-1{--sd-gutter-x: 0.25rem}.sd-g-2,.sd-gy-2{--sd-gutter-y: 0.5rem}.sd-g-2,.sd-gx-2{--sd-gutter-x: 0.5rem}.sd-g-3,.sd-gy-3{--sd-gutter-y: 1rem}.sd-g-3,.sd-gx-3{--sd-gutter-x: 1rem}.sd-g-4,.sd-gy-4{--sd-gutter-y: 1.5rem}.sd-g-4,.sd-gx-4{--sd-gutter-x: 1.5rem}.sd-g-5,.sd-gy-5{--sd-gutter-y: 3rem}.sd-g-5,.sd-gx-5{--sd-gutter-x: 3rem}@media(min-width: 576px){.sd-col-sm-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto}.sd-col-sm-1{-ms-flex:0 0 auto;flex:0 0 auto;width:8.3333333333%}.sd-col-sm-2{-ms-flex:0 0 auto;flex:0 0 auto;width:16.6666666667%}.sd-col-sm-3{-ms-flex:0 0 auto;flex:0 0 auto;width:25%}.sd-col-sm-4{-ms-flex:0 0 auto;flex:0 0 auto;width:33.3333333333%}.sd-col-sm-5{-ms-flex:0 0 auto;flex:0 0 auto;width:41.6666666667%}.sd-col-sm-6{-ms-flex:0 0 auto;flex:0 0 auto;width:50%}.sd-col-sm-7{-ms-flex:0 0 auto;flex:0 0 auto;width:58.3333333333%}.sd-col-sm-8{-ms-flex:0 0 auto;flex:0 0 auto;width:66.6666666667%}.sd-col-sm-9{-ms-flex:0 0 auto;flex:0 0 auto;width:75%}.sd-col-sm-10{-ms-flex:0 0 auto;flex:0 0 auto;width:83.3333333333%}.sd-col-sm-11{-ms-flex:0 0 auto;flex:0 0 auto;width:91.6666666667%}.sd-col-sm-12{-ms-flex:0 0 auto;flex:0 0 auto;width:100%}.sd-g-sm-0,.sd-gy-sm-0{--sd-gutter-y: 0}.sd-g-sm-0,.sd-gx-sm-0{--sd-gutter-x: 0}.sd-g-sm-1,.sd-gy-sm-1{--sd-gutter-y: 0.25rem}.sd-g-sm-1,.sd-gx-sm-1{--sd-gutter-x: 0.25rem}.sd-g-sm-2,.sd-gy-sm-2{--sd-gutter-y: 0.5rem}.sd-g-sm-2,.sd-gx-sm-2{--sd-gutter-x: 0.5rem}.sd-g-sm-3,.sd-gy-sm-3{--sd-gutter-y: 1rem}.sd-g-sm-3,.sd-gx-sm-3{--sd-gutter-x: 1rem}.sd-g-sm-4,.sd-gy-sm-4{--sd-gutter-y: 1.5rem}.sd-g-sm-4,.sd-gx-sm-4{--sd-gutter-x: 1.5rem}.sd-g-sm-5,.sd-gy-sm-5{--sd-gutter-y: 3rem}.sd-g-sm-5,.sd-gx-sm-5{--sd-gutter-x: 3rem}}@media(min-width: 768px){.sd-col-md-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto}.sd-col-md-1{-ms-flex:0 0 auto;flex:0 0 auto;width:8.3333333333%}.sd-col-md-2{-ms-flex:0 0 auto;flex:0 0 auto;width:16.6666666667%}.sd-col-md-3{-ms-flex:0 0 auto;flex:0 0 auto;width:25%}.sd-col-md-4{-ms-flex:0 0 auto;flex:0 0 auto;width:33.3333333333%}.sd-col-md-5{-ms-flex:0 0 auto;flex:0 0 auto;width:41.6666666667%}.sd-col-md-6{-ms-flex:0 0 auto;flex:0 0 auto;width:50%}.sd-col-md-7{-ms-flex:0 0 auto;flex:0 0 auto;width:58.3333333333%}.sd-col-md-8{-ms-flex:0 0 auto;flex:0 0 auto;width:66.6666666667%}.sd-col-md-9{-ms-flex:0 0 auto;flex:0 0 auto;width:75%}.sd-col-md-10{-ms-flex:0 0 auto;flex:0 0 auto;width:83.3333333333%}.sd-col-md-11{-ms-flex:0 0 auto;flex:0 0 auto;width:91.6666666667%}.sd-col-md-12{-ms-flex:0 0 auto;flex:0 0 auto;width:100%}.sd-g-md-0,.sd-gy-md-0{--sd-gutter-y: 0}.sd-g-md-0,.sd-gx-md-0{--sd-gutter-x: 0}.sd-g-md-1,.sd-gy-md-1{--sd-gutter-y: 0.25rem}.sd-g-md-1,.sd-gx-md-1{--sd-gutter-x: 0.25rem}.sd-g-md-2,.sd-gy-md-2{--sd-gutter-y: 0.5rem}.sd-g-md-2,.sd-gx-md-2{--sd-gutter-x: 0.5rem}.sd-g-md-3,.sd-gy-md-3{--sd-gutter-y: 1rem}.sd-g-md-3,.sd-gx-md-3{--sd-gutter-x: 1rem}.sd-g-md-4,.sd-gy-md-4{--sd-gutter-y: 1.5rem}.sd-g-md-4,.sd-gx-md-4{--sd-gutter-x: 1.5rem}.sd-g-md-5,.sd-gy-md-5{--sd-gutter-y: 3rem}.sd-g-md-5,.sd-gx-md-5{--sd-gutter-x: 3rem}}@media(min-width: 992px){.sd-col-lg-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto}.sd-col-lg-1{-ms-flex:0 0 auto;flex:0 0 auto;width:8.3333333333%}.sd-col-lg-2{-ms-flex:0 0 auto;flex:0 0 auto;width:16.6666666667%}.sd-col-lg-3{-ms-flex:0 0 auto;flex:0 0 auto;width:25%}.sd-col-lg-4{-ms-flex:0 0 auto;flex:0 0 auto;width:33.3333333333%}.sd-col-lg-5{-ms-flex:0 0 auto;flex:0 0 auto;width:41.6666666667%}.sd-col-lg-6{-ms-flex:0 0 auto;flex:0 0 auto;width:50%}.sd-col-lg-7{-ms-flex:0 0 auto;flex:0 0 auto;width:58.3333333333%}.sd-col-lg-8{-ms-flex:0 0 auto;flex:0 0 auto;width:66.6666666667%}.sd-col-lg-9{-ms-flex:0 0 auto;flex:0 0 auto;width:75%}.sd-col-lg-10{-ms-flex:0 0 auto;flex:0 0 auto;width:83.3333333333%}.sd-col-lg-11{-ms-flex:0 0 auto;flex:0 0 auto;width:91.6666666667%}.sd-col-lg-12{-ms-flex:0 0 auto;flex:0 0 auto;width:100%}.sd-g-lg-0,.sd-gy-lg-0{--sd-gutter-y: 0}.sd-g-lg-0,.sd-gx-lg-0{--sd-gutter-x: 0}.sd-g-lg-1,.sd-gy-lg-1{--sd-gutter-y: 0.25rem}.sd-g-lg-1,.sd-gx-lg-1{--sd-gutter-x: 0.25rem}.sd-g-lg-2,.sd-gy-lg-2{--sd-gutter-y: 0.5rem}.sd-g-lg-2,.sd-gx-lg-2{--sd-gutter-x: 0.5rem}.sd-g-lg-3,.sd-gy-lg-3{--sd-gutter-y: 1rem}.sd-g-lg-3,.sd-gx-lg-3{--sd-gutter-x: 1rem}.sd-g-lg-4,.sd-gy-lg-4{--sd-gutter-y: 1.5rem}.sd-g-lg-4,.sd-gx-lg-4{--sd-gutter-x: 1.5rem}.sd-g-lg-5,.sd-gy-lg-5{--sd-gutter-y: 3rem}.sd-g-lg-5,.sd-gx-lg-5{--sd-gutter-x: 3rem}}@media(min-width: 1200px){.sd-col-xl-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto}.sd-col-xl-1{-ms-flex:0 0 auto;flex:0 0 auto;width:8.3333333333%}.sd-col-xl-2{-ms-flex:0 0 auto;flex:0 0 auto;width:16.6666666667%}.sd-col-xl-3{-ms-flex:0 0 auto;flex:0 0 auto;width:25%}.sd-col-xl-4{-ms-flex:0 0 auto;flex:0 0 auto;width:33.3333333333%}.sd-col-xl-5{-ms-flex:0 0 auto;flex:0 0 auto;width:41.6666666667%}.sd-col-xl-6{-ms-flex:0 0 auto;flex:0 0 auto;width:50%}.sd-col-xl-7{-ms-flex:0 0 auto;flex:0 0 auto;width:58.3333333333%}.sd-col-xl-8{-ms-flex:0 0 auto;flex:0 0 auto;width:66.6666666667%}.sd-col-xl-9{-ms-flex:0 0 auto;flex:0 0 auto;width:75%}.sd-col-xl-10{-ms-flex:0 0 auto;flex:0 0 auto;width:83.3333333333%}.sd-col-xl-11{-ms-flex:0 0 auto;flex:0 0 auto;width:91.6666666667%}.sd-col-xl-12{-ms-flex:0 0 auto;flex:0 0 auto;width:100%}.sd-g-xl-0,.sd-gy-xl-0{--sd-gutter-y: 0}.sd-g-xl-0,.sd-gx-xl-0{--sd-gutter-x: 0}.sd-g-xl-1,.sd-gy-xl-1{--sd-gutter-y: 0.25rem}.sd-g-xl-1,.sd-gx-xl-1{--sd-gutter-x: 0.25rem}.sd-g-xl-2,.sd-gy-xl-2{--sd-gutter-y: 0.5rem}.sd-g-xl-2,.sd-gx-xl-2{--sd-gutter-x: 0.5rem}.sd-g-xl-3,.sd-gy-xl-3{--sd-gutter-y: 1rem}.sd-g-xl-3,.sd-gx-xl-3{--sd-gutter-x: 1rem}.sd-g-xl-4,.sd-gy-xl-4{--sd-gutter-y: 1.5rem}.sd-g-xl-4,.sd-gx-xl-4{--sd-gutter-x: 1.5rem}.sd-g-xl-5,.sd-gy-xl-5{--sd-gutter-y: 3rem}.sd-g-xl-5,.sd-gx-xl-5{--sd-gutter-x: 3rem}}.sd-flex-row-reverse{flex-direction:row-reverse !important}details.sd-dropdown{position:relative}details.sd-dropdown .sd-summary-title{font-weight:700;padding-right:3em !important;-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none;user-select:none}details.sd-dropdown:hover{cursor:pointer}details.sd-dropdown .sd-summary-content{cursor:default}details.sd-dropdown summary{list-style:none;padding:1em}details.sd-dropdown summary .sd-octicon.no-title{vertical-align:middle}details.sd-dropdown[open] summary .sd-octicon.no-title{visibility:hidden}details.sd-dropdown summary::-webkit-details-marker{display:none}details.sd-dropdown summary:focus{outline:none}details.sd-dropdown .sd-summary-icon{margin-right:.5em}details.sd-dropdown .sd-summary-icon svg{opacity:.8}details.sd-dropdown summary:hover .sd-summary-up svg,details.sd-dropdown summary:hover .sd-summary-down svg{opacity:1;transform:scale(1.1)}details.sd-dropdown .sd-summary-up svg,details.sd-dropdown .sd-summary-down svg{display:block;opacity:.6}details.sd-dropdown .sd-summary-up,details.sd-dropdown .sd-summary-down{pointer-events:none;position:absolute;right:1em;top:1em}details.sd-dropdown[open]>.sd-summary-title .sd-summary-down{visibility:hidden}details.sd-dropdown:not([open])>.sd-summary-title .sd-summary-up{visibility:hidden}details.sd-dropdown:not([open]).sd-card{border:none}details.sd-dropdown:not([open])>.sd-card-header{border:1px solid var(--sd-color-card-border);border-radius:.25rem}details.sd-dropdown.sd-fade-in[open] summary~*{-moz-animation:sd-fade-in .5s ease-in-out;-webkit-animation:sd-fade-in .5s ease-in-out;animation:sd-fade-in .5s ease-in-out}details.sd-dropdown.sd-fade-in-slide-down[open] summary~*{-moz-animation:sd-fade-in .5s ease-in-out,sd-slide-down .5s ease-in-out;-webkit-animation:sd-fade-in .5s ease-in-out,sd-slide-down .5s ease-in-out;animation:sd-fade-in .5s ease-in-out,sd-slide-down .5s ease-in-out}.sd-col>.sd-dropdown{width:100%}.sd-summary-content>.sd-tab-set:first-child{margin-top:0}@keyframes sd-fade-in{0%{opacity:0}100%{opacity:1}}@keyframes sd-slide-down{0%{transform:translate(0, -10px)}100%{transform:translate(0, 0)}}.sd-tab-set{border-radius:.125rem;display:flex;flex-wrap:wrap;margin:1em 0;position:relative}.sd-tab-set>input{opacity:0;position:absolute}.sd-tab-set>input:checked+label{border-color:var(--sd-color-tabs-underline-active);color:var(--sd-color-tabs-label-active)}.sd-tab-set>input:checked+label+.sd-tab-content{display:block}.sd-tab-set>input:not(:checked)+label:hover{color:var(--sd-color-tabs-label-hover);border-color:var(--sd-color-tabs-underline-hover)}.sd-tab-set>input:focus+label{outline-style:auto}.sd-tab-set>input:not(.focus-visible)+label{outline:none;-webkit-tap-highlight-color:transparent}.sd-tab-set>label{border-bottom:.125rem solid transparent;margin-bottom:0;color:var(--sd-color-tabs-label-inactive);border-color:var(--sd-color-tabs-underline-inactive);cursor:pointer;font-size:var(--sd-fontsize-tabs-label);font-weight:700;padding:1em 1.25em .5em;transition:color 250ms;width:auto;z-index:1}html .sd-tab-set>label:hover{color:var(--sd-color-tabs-label-active)}.sd-col>.sd-tab-set{width:100%}.sd-tab-content{box-shadow:0 -0.0625rem var(--sd-color-tabs-overline),0 .0625rem var(--sd-color-tabs-underline);display:none;order:99;padding-bottom:.75rem;padding-top:.75rem;width:100%}.sd-tab-content>:first-child{margin-top:0 !important}.sd-tab-content>:last-child{margin-bottom:0 !important}.sd-tab-content>.sd-tab-set{margin:0}.sd-sphinx-override,.sd-sphinx-override *{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}.sd-sphinx-override p{margin-top:0}:root{--sd-color-primary: #0071bc;--sd-color-secondary: #6c757d;--sd-color-success: #28a745;--sd-color-info: #17a2b8;--sd-color-warning: #f0b37e;--sd-color-danger: #dc3545;--sd-color-light: #f8f9fa;--sd-color-muted: #6c757d;--sd-color-dark: #212529;--sd-color-black: black;--sd-color-white: white;--sd-color-primary-highlight: #0060a0;--sd-color-secondary-highlight: #5c636a;--sd-color-success-highlight: #228e3b;--sd-color-info-highlight: #148a9c;--sd-color-warning-highlight: #cc986b;--sd-color-danger-highlight: #bb2d3b;--sd-color-light-highlight: #d3d4d5;--sd-color-muted-highlight: #5c636a;--sd-color-dark-highlight: #1c1f23;--sd-color-black-highlight: black;--sd-color-white-highlight: #d9d9d9;--sd-color-primary-text: #fff;--sd-color-secondary-text: #fff;--sd-color-success-text: #fff;--sd-color-info-text: #fff;--sd-color-warning-text: #212529;--sd-color-danger-text: #fff;--sd-color-light-text: #212529;--sd-color-muted-text: #fff;--sd-color-dark-text: #fff;--sd-color-black-text: #fff;--sd-color-white-text: #212529;--sd-color-shadow: rgba(0, 0, 0, 0.15);--sd-color-card-border: rgba(0, 0, 0, 0.125);--sd-color-card-border-hover: hsla(231, 99%, 66%, 1);--sd-color-card-background: transparent;--sd-color-card-text: inherit;--sd-color-card-header: transparent;--sd-color-card-footer: transparent;--sd-color-tabs-label-active: hsla(231, 99%, 66%, 1);--sd-color-tabs-label-hover: hsla(231, 99%, 66%, 1);--sd-color-tabs-label-inactive: hsl(0, 0%, 66%);--sd-color-tabs-underline-active: hsla(231, 99%, 66%, 1);--sd-color-tabs-underline-hover: rgba(178, 206, 245, 0.62);--sd-color-tabs-underline-inactive: transparent;--sd-color-tabs-overline: rgb(222, 222, 222);--sd-color-tabs-underline: rgb(222, 222, 222);--sd-fontsize-tabs-label: 1rem} diff --git a/_static/design-tabs.js b/_static/design-tabs.js new file mode 100644 index 0000000..36b38cf --- /dev/null +++ b/_static/design-tabs.js @@ -0,0 +1,27 @@ +var sd_labels_by_text = {}; + +function ready() { + const li = document.getElementsByClassName("sd-tab-label"); + for (const label of li) { + syncId = label.getAttribute("data-sync-id"); + if (syncId) { + label.onclick = onLabelClick; + if (!sd_labels_by_text[syncId]) { + sd_labels_by_text[syncId] = []; + } + sd_labels_by_text[syncId].push(label); + } + } +} + +function onLabelClick() { + // Activate other inputs with the same sync id. + syncId = this.getAttribute("data-sync-id"); + for (label of sd_labels_by_text[syncId]) { + if (label === this) continue; + label.previousElementSibling.checked = true; + } + window.localStorage.setItem("sphinx-design-last-tab", syncId); +} + +document.addEventListener("DOMContentLoaded", ready, false); diff --git a/_static/doctools.js b/_static/doctools.js new file mode 100644 index 0000000..527b876 --- /dev/null +++ b/_static/doctools.js @@ -0,0 +1,156 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Base JavaScript utilities for all Sphinx HTML documentation. + * + * :copyright: Copyright 2007-2022 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +const BLACKLISTED_KEY_CONTROL_ELEMENTS = new Set([ + "TEXTAREA", + "INPUT", + "SELECT", + "BUTTON", +]); + +const _ready = (callback) => { + if (document.readyState !== "loading") { + callback(); + } else { + document.addEventListener("DOMContentLoaded", callback); + } +}; + +/** + * Small JavaScript module for the documentation. + */ +const Documentation = { + init: () => { + Documentation.initDomainIndexTable(); + Documentation.initOnKeyListeners(); + }, + + /** + * i18n support + */ + TRANSLATIONS: {}, + PLURAL_EXPR: (n) => (n === 1 ? 0 : 1), + LOCALE: "unknown", + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext: (string) => { + const translated = Documentation.TRANSLATIONS[string]; + switch (typeof translated) { + case "undefined": + return string; // no translation + case "string": + return translated; // translation exists + default: + return translated[0]; // (singular, plural) translation tuple exists + } + }, + + ngettext: (singular, plural, n) => { + const translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated !== "undefined") + return translated[Documentation.PLURAL_EXPR(n)]; + return n === 1 ? singular : plural; + }, + + addTranslations: (catalog) => { + Object.assign(Documentation.TRANSLATIONS, catalog.messages); + Documentation.PLURAL_EXPR = new Function( + "n", + `return (${catalog.plural_expr})` + ); + Documentation.LOCALE = catalog.locale; + }, + + /** + * helper function to focus on search bar + */ + focusSearchBar: () => { + document.querySelectorAll("input[name=q]")[0]?.focus(); + }, + + /** + * Initialise the domain index toggle buttons + */ + initDomainIndexTable: () => { + const toggler = (el) => { + const idNumber = el.id.substr(7); + const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`); + if (el.src.substr(-9) === "minus.png") { + el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`; + toggledRows.forEach((el) => (el.style.display = "none")); + } else { + el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`; + toggledRows.forEach((el) => (el.style.display = "")); + } + }; + + const togglerElements = document.querySelectorAll("img.toggler"); + togglerElements.forEach((el) => + el.addEventListener("click", (event) => toggler(event.currentTarget)) + ); + togglerElements.forEach((el) => (el.style.display = "")); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler); + }, + + initOnKeyListeners: () => { + // only install a listener if it is really needed + if ( + !DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS && + !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS + ) + return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.altKey || event.ctrlKey || event.metaKey) return; + + if (!event.shiftKey) { + switch (event.key) { + case "ArrowLeft": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const prevLink = document.querySelector('link[rel="prev"]'); + if (prevLink && prevLink.href) { + window.location.href = prevLink.href; + event.preventDefault(); + } + break; + case "ArrowRight": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const nextLink = document.querySelector('link[rel="next"]'); + if (nextLink && nextLink.href) { + window.location.href = nextLink.href; + event.preventDefault(); + } + break; + } + } + + // some keyboard layouts may need Shift to get / + switch (event.key) { + case "/": + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break; + Documentation.focusSearchBar(); + event.preventDefault(); + } + }); + }, +}; + +// quick alias for translations +const _ = Documentation.gettext; + +_ready(Documentation.init); diff --git a/_static/documentation_options.js b/_static/documentation_options.js new file mode 100644 index 0000000..30f4fb4 --- /dev/null +++ b/_static/documentation_options.js @@ -0,0 +1,14 @@ +var DOCUMENTATION_OPTIONS = { + URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), + VERSION: '2.0.0rc5', + LANGUAGE: 'en', + COLLAPSE_INDEX: false, + BUILDER: 'html', + FILE_SUFFIX: '.html', + LINK_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt', + NAVIGATION_WITH_KEYS: true, + SHOW_SEARCH_SUMMARY: true, + ENABLE_SEARCH_SHORTCUTS: true, +}; \ No newline at end of file diff --git a/_static/favicon.ico b/_static/favicon.ico new file mode 100644 index 0000000..ee0844c Binary files /dev/null and b/_static/favicon.ico differ diff --git a/_static/file.png b/_static/file.png new file mode 100644 index 0000000..a858a41 Binary files /dev/null and b/_static/file.png differ diff --git a/_static/gallery.css b/_static/gallery.css new file mode 100644 index 0000000..dbcf16e --- /dev/null +++ b/_static/gallery.css @@ -0,0 +1,32 @@ +ul.tab { + list-style-type: none; + padding: 0; + overflow: hidden; +} + +ul.tab li { + float: left; + padding: 0; +} + +ul.tab li label { + background: white; + padding: 6px; + border: 1px solid #ccc; + display: inline-block; +} + +ul.tab li input[type="radio"] { + opacity: 0; + width: 1px; + height: 1px; +} + +ul.tab li input[type="radio"]:checked ~ label { + background: var(--pst-color-primary); + color: white; +} + +dl.dl-horizontal { + padding-left: 50px; +} diff --git a/_static/graphviz.css b/_static/graphviz.css new file mode 100644 index 0000000..19e7afd --- /dev/null +++ b/_static/graphviz.css @@ -0,0 +1,19 @@ +/* + * graphviz.css + * ~~~~~~~~~~~~ + * + * Sphinx stylesheet -- graphviz extension. + * + * :copyright: Copyright 2007-2022 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +img.graphviz { + border: 0; + max-width: 100%; +} + +object.graphviz { + max-width: 100%; +} diff --git a/_static/holoviz-icon-white.svg b/_static/holoviz-icon-white.svg new file mode 100644 index 0000000..0089fb1 --- /dev/null +++ b/_static/holoviz-icon-white.svg @@ -0,0 +1,209 @@ + + + +image/svg+xml diff --git a/_static/icon.png b/_static/icon.png new file mode 100644 index 0000000..b9727d5 Binary files /dev/null and b/_static/icon.png differ diff --git a/_static/icon.svg b/_static/icon.svg new file mode 100644 index 0000000..ed61ab3 --- /dev/null +++ b/_static/icon.svg @@ -0,0 +1,296 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_static/jquery-3.6.0.js b/_static/jquery-3.6.0.js new file mode 100644 index 0000000..fc6c299 --- /dev/null +++ b/_static/jquery-3.6.0.js @@ -0,0 +1,10881 @@ +/*! + * jQuery JavaScript Library v3.6.0 + * https://jquery.com/ + * + * Includes Sizzle.js + * https://sizzlejs.com/ + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license + * https://jquery.org/license + * + * Date: 2021-03-02T17:08Z + */ +( function( global, factory ) { + + "use strict"; + + if ( typeof module === "object" && typeof module.exports === "object" ) { + + // For CommonJS and CommonJS-like environments where a proper `window` + // is present, execute the factory and get jQuery. + // For environments that do not have a `window` with a `document` + // (such as Node.js), expose a factory as module.exports. + // This accentuates the need for the creation of a real `window`. + // e.g. var jQuery = require("jquery")(window); + // See ticket #14549 for more info. + module.exports = global.document ? + factory( global, true ) : + function( w ) { + if ( !w.document ) { + throw new Error( "jQuery requires a window with a document" ); + } + return factory( w ); + }; + } else { + factory( global ); + } + +// Pass this if window is not defined yet +} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) { + +// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 +// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode +// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common +// enough that all such attempts are guarded in a try block. +"use strict"; + +var arr = []; + +var getProto = Object.getPrototypeOf; + +var slice = arr.slice; + +var flat = arr.flat ? function( array ) { + return arr.flat.call( array ); +} : function( array ) { + return arr.concat.apply( [], array ); +}; + + +var push = arr.push; + +var indexOf = arr.indexOf; + +var class2type = {}; + +var toString = class2type.toString; + +var hasOwn = class2type.hasOwnProperty; + +var fnToString = hasOwn.toString; + +var ObjectFunctionString = fnToString.call( Object ); + +var support = {}; + +var isFunction = function isFunction( obj ) { + + // Support: Chrome <=57, Firefox <=52 + // In some browsers, typeof returns "function" for HTML elements + // (i.e., `typeof document.createElement( "object" ) === "function"`). + // We don't want to classify *any* DOM node as a function. + // Support: QtWeb <=3.8.5, WebKit <=534.34, wkhtmltopdf tool <=0.12.5 + // Plus for old WebKit, typeof returns "function" for HTML collections + // (e.g., `typeof document.getElementsByTagName("div") === "function"`). (gh-4756) + return typeof obj === "function" && typeof obj.nodeType !== "number" && + typeof obj.item !== "function"; + }; + + +var isWindow = function isWindow( obj ) { + return obj != null && obj === obj.window; + }; + + +var document = window.document; + + + + var preservedScriptAttributes = { + type: true, + src: true, + nonce: true, + noModule: true + }; + + function DOMEval( code, node, doc ) { + doc = doc || document; + + var i, val, + script = doc.createElement( "script" ); + + script.text = code; + if ( node ) { + for ( i in preservedScriptAttributes ) { + + // Support: Firefox 64+, Edge 18+ + // Some browsers don't support the "nonce" property on scripts. + // On the other hand, just using `getAttribute` is not enough as + // the `nonce` attribute is reset to an empty string whenever it + // becomes browsing-context connected. + // See https://github.com/whatwg/html/issues/2369 + // See https://html.spec.whatwg.org/#nonce-attributes + // The `node.getAttribute` check was added for the sake of + // `jQuery.globalEval` so that it can fake a nonce-containing node + // via an object. + val = node[ i ] || node.getAttribute && node.getAttribute( i ); + if ( val ) { + script.setAttribute( i, val ); + } + } + } + doc.head.appendChild( script ).parentNode.removeChild( script ); + } + + +function toType( obj ) { + if ( obj == null ) { + return obj + ""; + } + + // Support: Android <=2.3 only (functionish RegExp) + return typeof obj === "object" || typeof obj === "function" ? + class2type[ toString.call( obj ) ] || "object" : + typeof obj; +} +/* global Symbol */ +// Defining this global in .eslintrc.json would create a danger of using the global +// unguarded in another place, it seems safer to define global only for this module + + + +var + version = "3.6.0", + + // Define a local copy of jQuery + jQuery = function( selector, context ) { + + // The jQuery object is actually just the init constructor 'enhanced' + // Need init if jQuery is called (just allow error to be thrown if not included) + return new jQuery.fn.init( selector, context ); + }; + +jQuery.fn = jQuery.prototype = { + + // The current version of jQuery being used + jquery: version, + + constructor: jQuery, + + // The default length of a jQuery object is 0 + length: 0, + + toArray: function() { + return slice.call( this ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + + // Return all the elements in a clean array + if ( num == null ) { + return slice.call( this ); + } + + // Return just the one element from the set + return num < 0 ? this[ num + this.length ] : this[ num ]; + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems ) { + + // Build a new jQuery matched element set + var ret = jQuery.merge( this.constructor(), elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + each: function( callback ) { + return jQuery.each( this, callback ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map( this, function( elem, i ) { + return callback.call( elem, i, elem ); + } ) ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ) ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + even: function() { + return this.pushStack( jQuery.grep( this, function( _elem, i ) { + return ( i + 1 ) % 2; + } ) ); + }, + + odd: function() { + return this.pushStack( jQuery.grep( this, function( _elem, i ) { + return i % 2; + } ) ); + }, + + eq: function( i ) { + var len = this.length, + j = +i + ( i < 0 ? len : 0 ); + return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); + }, + + end: function() { + return this.prevObject || this.constructor(); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: arr.sort, + splice: arr.splice +}; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[ 0 ] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + + // Skip the boolean and the target + target = arguments[ i ] || {}; + i++; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !isFunction( target ) ) { + target = {}; + } + + // Extend jQuery itself if only one argument is passed + if ( i === length ) { + target = this; + i--; + } + + for ( ; i < length; i++ ) { + + // Only deal with non-null/undefined values + if ( ( options = arguments[ i ] ) != null ) { + + // Extend the base object + for ( name in options ) { + copy = options[ name ]; + + // Prevent Object.prototype pollution + // Prevent never-ending loop + if ( name === "__proto__" || target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject( copy ) || + ( copyIsArray = Array.isArray( copy ) ) ) ) { + src = target[ name ]; + + // Ensure proper type for the source value + if ( copyIsArray && !Array.isArray( src ) ) { + clone = []; + } else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) { + clone = {}; + } else { + clone = src; + } + copyIsArray = false; + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend( { + + // Unique for each copy of jQuery on the page + expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), + + // Assume jQuery is ready without the ready module + isReady: true, + + error: function( msg ) { + throw new Error( msg ); + }, + + noop: function() {}, + + isPlainObject: function( obj ) { + var proto, Ctor; + + // Detect obvious negatives + // Use toString instead of jQuery.type to catch host objects + if ( !obj || toString.call( obj ) !== "[object Object]" ) { + return false; + } + + proto = getProto( obj ); + + // Objects with no prototype (e.g., `Object.create( null )`) are plain + if ( !proto ) { + return true; + } + + // Objects with prototype are plain iff they were constructed by a global Object function + Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; + return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; + }, + + isEmptyObject: function( obj ) { + var name; + + for ( name in obj ) { + return false; + } + return true; + }, + + // Evaluates a script in a provided context; falls back to the global one + // if not specified. + globalEval: function( code, options, doc ) { + DOMEval( code, { nonce: options && options.nonce }, doc ); + }, + + each: function( obj, callback ) { + var length, i = 0; + + if ( isArrayLike( obj ) ) { + length = obj.length; + for ( ; i < length; i++ ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } else { + for ( i in obj ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } + + return obj; + }, + + // results is for internal usage only + makeArray: function( arr, results ) { + var ret = results || []; + + if ( arr != null ) { + if ( isArrayLike( Object( arr ) ) ) { + jQuery.merge( ret, + typeof arr === "string" ? + [ arr ] : arr + ); + } else { + push.call( ret, arr ); + } + } + + return ret; + }, + + inArray: function( elem, arr, i ) { + return arr == null ? -1 : indexOf.call( arr, elem, i ); + }, + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + merge: function( first, second ) { + var len = +second.length, + j = 0, + i = first.length; + + for ( ; j < len; j++ ) { + first[ i++ ] = second[ j ]; + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, invert ) { + var callbackInverse, + matches = [], + i = 0, + length = elems.length, + callbackExpect = !invert; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + callbackInverse = !callback( elems[ i ], i ); + if ( callbackInverse !== callbackExpect ) { + matches.push( elems[ i ] ); + } + } + + return matches; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var length, value, + i = 0, + ret = []; + + // Go through the array, translating each of the items to their new values + if ( isArrayLike( elems ) ) { + length = elems.length; + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + + // Go through every key on the object, + } else { + for ( i in elems ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + } + + // Flatten any nested arrays + return flat( ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // jQuery.support is not used in Core but other projects attach their + // properties to it so it needs to exist. + support: support +} ); + +if ( typeof Symbol === "function" ) { + jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; +} + +// Populate the class2type map +jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), + function( _i, name ) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); + } ); + +function isArrayLike( obj ) { + + // Support: real iOS 8.2 only (not reproducible in simulator) + // `in` check used to prevent JIT error (gh-2145) + // hasOwn isn't used here due to false negatives + // regarding Nodelist length in IE + var length = !!obj && "length" in obj && obj.length, + type = toType( obj ); + + if ( isFunction( obj ) || isWindow( obj ) ) { + return false; + } + + return type === "array" || length === 0 || + typeof length === "number" && length > 0 && ( length - 1 ) in obj; +} +var Sizzle = +/*! + * Sizzle CSS Selector Engine v2.3.6 + * https://sizzlejs.com/ + * + * Copyright JS Foundation and other contributors + * Released under the MIT license + * https://js.foundation/ + * + * Date: 2021-02-16 + */ +( function( window ) { +var i, + support, + Expr, + getText, + isXML, + tokenize, + compile, + select, + outermostContext, + sortInput, + hasDuplicate, + + // Local document vars + setDocument, + document, + docElem, + documentIsHTML, + rbuggyQSA, + rbuggyMatches, + matches, + contains, + + // Instance-specific data + expando = "sizzle" + 1 * new Date(), + preferredDoc = window.document, + dirruns = 0, + done = 0, + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + nonnativeSelectorCache = createCache(), + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + } + return 0; + }, + + // Instance methods + hasOwn = ( {} ).hasOwnProperty, + arr = [], + pop = arr.pop, + pushNative = arr.push, + push = arr.push, + slice = arr.slice, + + // Use a stripped-down indexOf as it's faster than native + // https://jsperf.com/thor-indexof-vs-for/5 + indexOf = function( list, elem ) { + var i = 0, + len = list.length; + for ( ; i < len; i++ ) { + if ( list[ i ] === elem ) { + return i; + } + } + return -1; + }, + + booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|" + + "ismap|loop|multiple|open|readonly|required|scoped", + + // Regular expressions + + // http://www.w3.org/TR/css3-selectors/#whitespace + whitespace = "[\\x20\\t\\r\\n\\f]", + + // https://www.w3.org/TR/css-syntax-3/#ident-token-diagram + identifier = "(?:\\\\[\\da-fA-F]{1,6}" + whitespace + + "?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+", + + // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors + attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + + + // Operator (capture 2) + "*([*^$|!~]?=)" + whitespace + + + // "Attribute values must be CSS identifiers [capture 5] + // or strings [capture 3 or capture 4]" + "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + + whitespace + "*\\]", + + pseudos = ":(" + identifier + ")(?:\\((" + + + // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: + // 1. quoted (capture 3; capture 4 or capture 5) + "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + + + // 2. simple (capture 6) + "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + + + // 3. anything else (capture 2) + ".*" + + ")\\)|)", + + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rwhitespace = new RegExp( whitespace + "+", "g" ), + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + + whitespace + "+$", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + + "*" ), + rdescend = new RegExp( whitespace + "|>" ), + + rpseudo = new RegExp( pseudos ), + ridentifier = new RegExp( "^" + identifier + "$" ), + + matchExpr = { + "ID": new RegExp( "^#(" + identifier + ")" ), + "CLASS": new RegExp( "^\\.(" + identifier + ")" ), + "TAG": new RegExp( "^(" + identifier + "|[*])" ), + "ATTR": new RegExp( "^" + attributes ), + "PSEUDO": new RegExp( "^" + pseudos ), + "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + + whitespace + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + + whitespace + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), + + // For use in libraries implementing .is() + // We use this for POS matching in `select` + "needsContext": new RegExp( "^" + whitespace + + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace + + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) + }, + + rhtml = /HTML$/i, + rinputs = /^(?:input|select|textarea|button)$/i, + rheader = /^h\d$/i, + + rnative = /^[^{]+\{\s*\[native \w/, + + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, + + rsibling = /[+~]/, + + // CSS escapes + // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = new RegExp( "\\\\[\\da-fA-F]{1,6}" + whitespace + "?|\\\\([^\\r\\n\\f])", "g" ), + funescape = function( escape, nonHex ) { + var high = "0x" + escape.slice( 1 ) - 0x10000; + + return nonHex ? + + // Strip the backslash prefix from a non-hex escape sequence + nonHex : + + // Replace a hexadecimal escape sequence with the encoded Unicode code point + // Support: IE <=11+ + // For values outside the Basic Multilingual Plane (BMP), manually construct a + // surrogate pair + high < 0 ? + String.fromCharCode( high + 0x10000 ) : + String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); + }, + + // CSS string/identifier serialization + // https://drafts.csswg.org/cssom/#common-serializing-idioms + rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g, + fcssescape = function( ch, asCodePoint ) { + if ( asCodePoint ) { + + // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER + if ( ch === "\0" ) { + return "\uFFFD"; + } + + // Control characters and (dependent upon position) numbers get escaped as code points + return ch.slice( 0, -1 ) + "\\" + + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; + } + + // Other potentially-special ASCII characters get backslash-escaped + return "\\" + ch; + }, + + // Used for iframes + // See setDocument() + // Removing the function wrapper causes a "Permission Denied" + // error in IE + unloadHandler = function() { + setDocument(); + }, + + inDisabledFieldset = addCombinator( + function( elem ) { + return elem.disabled === true && elem.nodeName.toLowerCase() === "fieldset"; + }, + { dir: "parentNode", next: "legend" } + ); + +// Optimize for push.apply( _, NodeList ) +try { + push.apply( + ( arr = slice.call( preferredDoc.childNodes ) ), + preferredDoc.childNodes + ); + + // Support: Android<4.0 + // Detect silently failing push.apply + // eslint-disable-next-line no-unused-expressions + arr[ preferredDoc.childNodes.length ].nodeType; +} catch ( e ) { + push = { apply: arr.length ? + + // Leverage slice if possible + function( target, els ) { + pushNative.apply( target, slice.call( els ) ); + } : + + // Support: IE<9 + // Otherwise append directly + function( target, els ) { + var j = target.length, + i = 0; + + // Can't trust NodeList.length + while ( ( target[ j++ ] = els[ i++ ] ) ) {} + target.length = j - 1; + } + }; +} + +function Sizzle( selector, context, results, seed ) { + var m, i, elem, nid, match, groups, newSelector, + newContext = context && context.ownerDocument, + + // nodeType defaults to 9, since context defaults to document + nodeType = context ? context.nodeType : 9; + + results = results || []; + + // Return early from calls with invalid selector or context + if ( typeof selector !== "string" || !selector || + nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { + + return results; + } + + // Try to shortcut find operations (as opposed to filters) in HTML documents + if ( !seed ) { + setDocument( context ); + context = context || document; + + if ( documentIsHTML ) { + + // If the selector is sufficiently simple, try using a "get*By*" DOM method + // (excepting DocumentFragment context, where the methods don't exist) + if ( nodeType !== 11 && ( match = rquickExpr.exec( selector ) ) ) { + + // ID selector + if ( ( m = match[ 1 ] ) ) { + + // Document context + if ( nodeType === 9 ) { + if ( ( elem = context.getElementById( m ) ) ) { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( elem.id === m ) { + results.push( elem ); + return results; + } + } else { + return results; + } + + // Element context + } else { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( newContext && ( elem = newContext.getElementById( m ) ) && + contains( context, elem ) && + elem.id === m ) { + + results.push( elem ); + return results; + } + } + + // Type selector + } else if ( match[ 2 ] ) { + push.apply( results, context.getElementsByTagName( selector ) ); + return results; + + // Class selector + } else if ( ( m = match[ 3 ] ) && support.getElementsByClassName && + context.getElementsByClassName ) { + + push.apply( results, context.getElementsByClassName( m ) ); + return results; + } + } + + // Take advantage of querySelectorAll + if ( support.qsa && + !nonnativeSelectorCache[ selector + " " ] && + ( !rbuggyQSA || !rbuggyQSA.test( selector ) ) && + + // Support: IE 8 only + // Exclude object elements + ( nodeType !== 1 || context.nodeName.toLowerCase() !== "object" ) ) { + + newSelector = selector; + newContext = context; + + // qSA considers elements outside a scoping root when evaluating child or + // descendant combinators, which is not what we want. + // In such cases, we work around the behavior by prefixing every selector in the + // list with an ID selector referencing the scope context. + // The technique has to be used as well when a leading combinator is used + // as such selectors are not recognized by querySelectorAll. + // Thanks to Andrew Dupont for this technique. + if ( nodeType === 1 && + ( rdescend.test( selector ) || rcombinators.test( selector ) ) ) { + + // Expand context for sibling selectors + newContext = rsibling.test( selector ) && testContext( context.parentNode ) || + context; + + // We can use :scope instead of the ID hack if the browser + // supports it & if we're not changing the context. + if ( newContext !== context || !support.scope ) { + + // Capture the context ID, setting it first if necessary + if ( ( nid = context.getAttribute( "id" ) ) ) { + nid = nid.replace( rcssescape, fcssescape ); + } else { + context.setAttribute( "id", ( nid = expando ) ); + } + } + + // Prefix every selector in the list + groups = tokenize( selector ); + i = groups.length; + while ( i-- ) { + groups[ i ] = ( nid ? "#" + nid : ":scope" ) + " " + + toSelector( groups[ i ] ); + } + newSelector = groups.join( "," ); + } + + try { + push.apply( results, + newContext.querySelectorAll( newSelector ) + ); + return results; + } catch ( qsaError ) { + nonnativeSelectorCache( selector, true ); + } finally { + if ( nid === expando ) { + context.removeAttribute( "id" ); + } + } + } + } + } + + // All others + return select( selector.replace( rtrim, "$1" ), context, results, seed ); +} + +/** + * Create key-value caches of limited size + * @returns {function(string, object)} Returns the Object data after storing it on itself with + * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) + * deleting the oldest entry + */ +function createCache() { + var keys = []; + + function cache( key, value ) { + + // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) + if ( keys.push( key + " " ) > Expr.cacheLength ) { + + // Only keep the most recent entries + delete cache[ keys.shift() ]; + } + return ( cache[ key + " " ] = value ); + } + return cache; +} + +/** + * Mark a function for special use by Sizzle + * @param {Function} fn The function to mark + */ +function markFunction( fn ) { + fn[ expando ] = true; + return fn; +} + +/** + * Support testing using an element + * @param {Function} fn Passed the created element and returns a boolean result + */ +function assert( fn ) { + var el = document.createElement( "fieldset" ); + + try { + return !!fn( el ); + } catch ( e ) { + return false; + } finally { + + // Remove from its parent by default + if ( el.parentNode ) { + el.parentNode.removeChild( el ); + } + + // release memory in IE + el = null; + } +} + +/** + * Adds the same handler for all of the specified attrs + * @param {String} attrs Pipe-separated list of attributes + * @param {Function} handler The method that will be applied + */ +function addHandle( attrs, handler ) { + var arr = attrs.split( "|" ), + i = arr.length; + + while ( i-- ) { + Expr.attrHandle[ arr[ i ] ] = handler; + } +} + +/** + * Checks document order of two siblings + * @param {Element} a + * @param {Element} b + * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b + */ +function siblingCheck( a, b ) { + var cur = b && a, + diff = cur && a.nodeType === 1 && b.nodeType === 1 && + a.sourceIndex - b.sourceIndex; + + // Use IE sourceIndex if available on both nodes + if ( diff ) { + return diff; + } + + // Check if b follows a + if ( cur ) { + while ( ( cur = cur.nextSibling ) ) { + if ( cur === b ) { + return -1; + } + } + } + + return a ? 1 : -1; +} + +/** + * Returns a function to use in pseudos for input types + * @param {String} type + */ +function createInputPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for buttons + * @param {String} type + */ +function createButtonPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return ( name === "input" || name === "button" ) && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for :enabled/:disabled + * @param {Boolean} disabled true for :disabled; false for :enabled + */ +function createDisabledPseudo( disabled ) { + + // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable + return function( elem ) { + + // Only certain elements can match :enabled or :disabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled + if ( "form" in elem ) { + + // Check for inherited disabledness on relevant non-disabled elements: + // * listed form-associated elements in a disabled fieldset + // https://html.spec.whatwg.org/multipage/forms.html#category-listed + // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled + // * option elements in a disabled optgroup + // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled + // All such elements have a "form" property. + if ( elem.parentNode && elem.disabled === false ) { + + // Option elements defer to a parent optgroup if present + if ( "label" in elem ) { + if ( "label" in elem.parentNode ) { + return elem.parentNode.disabled === disabled; + } else { + return elem.disabled === disabled; + } + } + + // Support: IE 6 - 11 + // Use the isDisabled shortcut property to check for disabled fieldset ancestors + return elem.isDisabled === disabled || + + // Where there is no isDisabled, check manually + /* jshint -W018 */ + elem.isDisabled !== !disabled && + inDisabledFieldset( elem ) === disabled; + } + + return elem.disabled === disabled; + + // Try to winnow out elements that can't be disabled before trusting the disabled property. + // Some victims get caught in our net (label, legend, menu, track), but it shouldn't + // even exist on them, let alone have a boolean value. + } else if ( "label" in elem ) { + return elem.disabled === disabled; + } + + // Remaining elements are neither :enabled nor :disabled + return false; + }; +} + +/** + * Returns a function to use in pseudos for positionals + * @param {Function} fn + */ +function createPositionalPseudo( fn ) { + return markFunction( function( argument ) { + argument = +argument; + return markFunction( function( seed, matches ) { + var j, + matchIndexes = fn( [], seed.length, argument ), + i = matchIndexes.length; + + // Match elements found at the specified indexes + while ( i-- ) { + if ( seed[ ( j = matchIndexes[ i ] ) ] ) { + seed[ j ] = !( matches[ j ] = seed[ j ] ); + } + } + } ); + } ); +} + +/** + * Checks a node for validity as a Sizzle context + * @param {Element|Object=} context + * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value + */ +function testContext( context ) { + return context && typeof context.getElementsByTagName !== "undefined" && context; +} + +// Expose support vars for convenience +support = Sizzle.support = {}; + +/** + * Detects XML nodes + * @param {Element|Object} elem An element or a document + * @returns {Boolean} True iff elem is a non-HTML XML node + */ +isXML = Sizzle.isXML = function( elem ) { + var namespace = elem && elem.namespaceURI, + docElem = elem && ( elem.ownerDocument || elem ).documentElement; + + // Support: IE <=8 + // Assume HTML when documentElement doesn't yet exist, such as inside loading iframes + // https://bugs.jquery.com/ticket/4833 + return !rhtml.test( namespace || docElem && docElem.nodeName || "HTML" ); +}; + +/** + * Sets document-related variables once based on the current document + * @param {Element|Object} [doc] An element or document object to use to set the document + * @returns {Object} Returns the current document + */ +setDocument = Sizzle.setDocument = function( node ) { + var hasCompare, subWindow, + doc = node ? node.ownerDocument || node : preferredDoc; + + // Return early if doc is invalid or already selected + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( doc == document || doc.nodeType !== 9 || !doc.documentElement ) { + return document; + } + + // Update global variables + document = doc; + docElem = document.documentElement; + documentIsHTML = !isXML( document ); + + // Support: IE 9 - 11+, Edge 12 - 18+ + // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( preferredDoc != document && + ( subWindow = document.defaultView ) && subWindow.top !== subWindow ) { + + // Support: IE 11, Edge + if ( subWindow.addEventListener ) { + subWindow.addEventListener( "unload", unloadHandler, false ); + + // Support: IE 9 - 10 only + } else if ( subWindow.attachEvent ) { + subWindow.attachEvent( "onunload", unloadHandler ); + } + } + + // Support: IE 8 - 11+, Edge 12 - 18+, Chrome <=16 - 25 only, Firefox <=3.6 - 31 only, + // Safari 4 - 5 only, Opera <=11.6 - 12.x only + // IE/Edge & older browsers don't support the :scope pseudo-class. + // Support: Safari 6.0 only + // Safari 6.0 supports :scope but it's an alias of :root there. + support.scope = assert( function( el ) { + docElem.appendChild( el ).appendChild( document.createElement( "div" ) ); + return typeof el.querySelectorAll !== "undefined" && + !el.querySelectorAll( ":scope fieldset div" ).length; + } ); + + /* Attributes + ---------------------------------------------------------------------- */ + + // Support: IE<8 + // Verify that getAttribute really returns attributes and not properties + // (excepting IE8 booleans) + support.attributes = assert( function( el ) { + el.className = "i"; + return !el.getAttribute( "className" ); + } ); + + /* getElement(s)By* + ---------------------------------------------------------------------- */ + + // Check if getElementsByTagName("*") returns only elements + support.getElementsByTagName = assert( function( el ) { + el.appendChild( document.createComment( "" ) ); + return !el.getElementsByTagName( "*" ).length; + } ); + + // Support: IE<9 + support.getElementsByClassName = rnative.test( document.getElementsByClassName ); + + // Support: IE<10 + // Check if getElementById returns elements by name + // The broken getElementById methods don't pick up programmatically-set names, + // so use a roundabout getElementsByName test + support.getById = assert( function( el ) { + docElem.appendChild( el ).id = expando; + return !document.getElementsByName || !document.getElementsByName( expando ).length; + } ); + + // ID filter and find + if ( support.getById ) { + Expr.filter[ "ID" ] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + return elem.getAttribute( "id" ) === attrId; + }; + }; + Expr.find[ "ID" ] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var elem = context.getElementById( id ); + return elem ? [ elem ] : []; + } + }; + } else { + Expr.filter[ "ID" ] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + var node = typeof elem.getAttributeNode !== "undefined" && + elem.getAttributeNode( "id" ); + return node && node.value === attrId; + }; + }; + + // Support: IE 6 - 7 only + // getElementById is not reliable as a find shortcut + Expr.find[ "ID" ] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var node, i, elems, + elem = context.getElementById( id ); + + if ( elem ) { + + // Verify the id attribute + node = elem.getAttributeNode( "id" ); + if ( node && node.value === id ) { + return [ elem ]; + } + + // Fall back on getElementsByName + elems = context.getElementsByName( id ); + i = 0; + while ( ( elem = elems[ i++ ] ) ) { + node = elem.getAttributeNode( "id" ); + if ( node && node.value === id ) { + return [ elem ]; + } + } + } + + return []; + } + }; + } + + // Tag + Expr.find[ "TAG" ] = support.getElementsByTagName ? + function( tag, context ) { + if ( typeof context.getElementsByTagName !== "undefined" ) { + return context.getElementsByTagName( tag ); + + // DocumentFragment nodes don't have gEBTN + } else if ( support.qsa ) { + return context.querySelectorAll( tag ); + } + } : + + function( tag, context ) { + var elem, + tmp = [], + i = 0, + + // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too + results = context.getElementsByTagName( tag ); + + // Filter out possible comments + if ( tag === "*" ) { + while ( ( elem = results[ i++ ] ) ) { + if ( elem.nodeType === 1 ) { + tmp.push( elem ); + } + } + + return tmp; + } + return results; + }; + + // Class + Expr.find[ "CLASS" ] = support.getElementsByClassName && function( className, context ) { + if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { + return context.getElementsByClassName( className ); + } + }; + + /* QSA/matchesSelector + ---------------------------------------------------------------------- */ + + // QSA and matchesSelector support + + // matchesSelector(:active) reports false when true (IE9/Opera 11.5) + rbuggyMatches = []; + + // qSa(:focus) reports false when true (Chrome 21) + // We allow this because of a bug in IE8/9 that throws an error + // whenever `document.activeElement` is accessed on an iframe + // So, we allow :focus to pass through QSA all the time to avoid the IE error + // See https://bugs.jquery.com/ticket/13378 + rbuggyQSA = []; + + if ( ( support.qsa = rnative.test( document.querySelectorAll ) ) ) { + + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert( function( el ) { + + var input; + + // Select is set to empty string on purpose + // This is to test IE's treatment of not explicitly + // setting a boolean content attribute, + // since its presence should be enough + // https://bugs.jquery.com/ticket/12359 + docElem.appendChild( el ).innerHTML = "" + + ""; + + // Support: IE8, Opera 11-12.16 + // Nothing should be selected when empty strings follow ^= or $= or *= + // The test attribute must be unknown in Opera but "safe" for WinRT + // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section + if ( el.querySelectorAll( "[msallowcapture^='']" ).length ) { + rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); + } + + // Support: IE8 + // Boolean attributes and "value" are not treated correctly + if ( !el.querySelectorAll( "[selected]" ).length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); + } + + // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ + if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) { + rbuggyQSA.push( "~=" ); + } + + // Support: IE 11+, Edge 15 - 18+ + // IE 11/Edge don't find elements on a `[name='']` query in some cases. + // Adding a temporary attribute to the document before the selection works + // around the issue. + // Interestingly, IE 10 & older don't seem to have the issue. + input = document.createElement( "input" ); + input.setAttribute( "name", "" ); + el.appendChild( input ); + if ( !el.querySelectorAll( "[name='']" ).length ) { + rbuggyQSA.push( "\\[" + whitespace + "*name" + whitespace + "*=" + + whitespace + "*(?:''|\"\")" ); + } + + // Webkit/Opera - :checked should return selected option elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + // IE8 throws error here and will not see later tests + if ( !el.querySelectorAll( ":checked" ).length ) { + rbuggyQSA.push( ":checked" ); + } + + // Support: Safari 8+, iOS 8+ + // https://bugs.webkit.org/show_bug.cgi?id=136851 + // In-page `selector#id sibling-combinator selector` fails + if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) { + rbuggyQSA.push( ".#.+[+~]" ); + } + + // Support: Firefox <=3.6 - 5 only + // Old Firefox doesn't throw on a badly-escaped identifier. + el.querySelectorAll( "\\\f" ); + rbuggyQSA.push( "[\\r\\n\\f]" ); + } ); + + assert( function( el ) { + el.innerHTML = "" + + ""; + + // Support: Windows 8 Native Apps + // The type and name attributes are restricted during .innerHTML assignment + var input = document.createElement( "input" ); + input.setAttribute( "type", "hidden" ); + el.appendChild( input ).setAttribute( "name", "D" ); + + // Support: IE8 + // Enforce case-sensitivity of name attribute + if ( el.querySelectorAll( "[name=d]" ).length ) { + rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); + } + + // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) + // IE8 throws error here and will not see later tests + if ( el.querySelectorAll( ":enabled" ).length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: IE9-11+ + // IE's :disabled selector does not pick up the children of disabled fieldsets + docElem.appendChild( el ).disabled = true; + if ( el.querySelectorAll( ":disabled" ).length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: Opera 10 - 11 only + // Opera 10-11 does not throw on post-comma invalid pseudos + el.querySelectorAll( "*,:x" ); + rbuggyQSA.push( ",.*:" ); + } ); + } + + if ( ( support.matchesSelector = rnative.test( ( matches = docElem.matches || + docElem.webkitMatchesSelector || + docElem.mozMatchesSelector || + docElem.oMatchesSelector || + docElem.msMatchesSelector ) ) ) ) { + + assert( function( el ) { + + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9) + support.disconnectedMatch = matches.call( el, "*" ); + + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( el, "[s!='']:x" ); + rbuggyMatches.push( "!=", pseudos ); + } ); + } + + rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join( "|" ) ); + rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join( "|" ) ); + + /* Contains + ---------------------------------------------------------------------- */ + hasCompare = rnative.test( docElem.compareDocumentPosition ); + + // Element contains another + // Purposefully self-exclusive + // As in, an element does not contain itself + contains = hasCompare || rnative.test( docElem.contains ) ? + function( a, b ) { + var adown = a.nodeType === 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a === bup || !!( bup && bup.nodeType === 1 && ( + adown.contains ? + adown.contains( bup ) : + a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 + ) ); + } : + function( a, b ) { + if ( b ) { + while ( ( b = b.parentNode ) ) { + if ( b === a ) { + return true; + } + } + } + return false; + }; + + /* Sorting + ---------------------------------------------------------------------- */ + + // Document order sorting + sortOrder = hasCompare ? + function( a, b ) { + + // Flag for duplicate removal + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + // Sort on method existence if only one input has compareDocumentPosition + var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; + if ( compare ) { + return compare; + } + + // Calculate position if both inputs belong to the same document + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + compare = ( a.ownerDocument || a ) == ( b.ownerDocument || b ) ? + a.compareDocumentPosition( b ) : + + // Otherwise we know they are disconnected + 1; + + // Disconnected nodes + if ( compare & 1 || + ( !support.sortDetached && b.compareDocumentPosition( a ) === compare ) ) { + + // Choose the first element that is related to our preferred document + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( a == document || a.ownerDocument == preferredDoc && + contains( preferredDoc, a ) ) { + return -1; + } + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( b == document || b.ownerDocument == preferredDoc && + contains( preferredDoc, b ) ) { + return 1; + } + + // Maintain original order + return sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + } + + return compare & 4 ? -1 : 1; + } : + function( a, b ) { + + // Exit early if the nodes are identical + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + var cur, + i = 0, + aup = a.parentNode, + bup = b.parentNode, + ap = [ a ], + bp = [ b ]; + + // Parentless nodes are either documents or disconnected + if ( !aup || !bup ) { + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + /* eslint-disable eqeqeq */ + return a == document ? -1 : + b == document ? 1 : + /* eslint-enable eqeqeq */ + aup ? -1 : + bup ? 1 : + sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + + // If the nodes are siblings, we can do a quick check + } else if ( aup === bup ) { + return siblingCheck( a, b ); + } + + // Otherwise we need full lists of their ancestors for comparison + cur = a; + while ( ( cur = cur.parentNode ) ) { + ap.unshift( cur ); + } + cur = b; + while ( ( cur = cur.parentNode ) ) { + bp.unshift( cur ); + } + + // Walk down the tree looking for a discrepancy + while ( ap[ i ] === bp[ i ] ) { + i++; + } + + return i ? + + // Do a sibling check if the nodes have a common ancestor + siblingCheck( ap[ i ], bp[ i ] ) : + + // Otherwise nodes in our document sort first + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + /* eslint-disable eqeqeq */ + ap[ i ] == preferredDoc ? -1 : + bp[ i ] == preferredDoc ? 1 : + /* eslint-enable eqeqeq */ + 0; + }; + + return document; +}; + +Sizzle.matches = function( expr, elements ) { + return Sizzle( expr, null, null, elements ); +}; + +Sizzle.matchesSelector = function( elem, expr ) { + setDocument( elem ); + + if ( support.matchesSelector && documentIsHTML && + !nonnativeSelectorCache[ expr + " " ] && + ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && + ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { + + try { + var ret = matches.call( elem, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || support.disconnectedMatch || + + // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11 ) { + return ret; + } + } catch ( e ) { + nonnativeSelectorCache( expr, true ); + } + } + + return Sizzle( expr, document, null, [ elem ] ).length > 0; +}; + +Sizzle.contains = function( context, elem ) { + + // Set document vars if needed + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( ( context.ownerDocument || context ) != document ) { + setDocument( context ); + } + return contains( context, elem ); +}; + +Sizzle.attr = function( elem, name ) { + + // Set document vars if needed + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( ( elem.ownerDocument || elem ) != document ) { + setDocument( elem ); + } + + var fn = Expr.attrHandle[ name.toLowerCase() ], + + // Don't get fooled by Object.prototype properties (jQuery #13807) + val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? + fn( elem, name, !documentIsHTML ) : + undefined; + + return val !== undefined ? + val : + support.attributes || !documentIsHTML ? + elem.getAttribute( name ) : + ( val = elem.getAttributeNode( name ) ) && val.specified ? + val.value : + null; +}; + +Sizzle.escape = function( sel ) { + return ( sel + "" ).replace( rcssescape, fcssescape ); +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +/** + * Document sorting and removing duplicates + * @param {ArrayLike} results + */ +Sizzle.uniqueSort = function( results ) { + var elem, + duplicates = [], + j = 0, + i = 0; + + // Unless we *know* we can detect duplicates, assume their presence + hasDuplicate = !support.detectDuplicates; + sortInput = !support.sortStable && results.slice( 0 ); + results.sort( sortOrder ); + + if ( hasDuplicate ) { + while ( ( elem = results[ i++ ] ) ) { + if ( elem === results[ i ] ) { + j = duplicates.push( i ); + } + } + while ( j-- ) { + results.splice( duplicates[ j ], 1 ); + } + } + + // Clear input after sorting to release objects + // See https://github.com/jquery/sizzle/pull/225 + sortInput = null; + + return results; +}; + +/** + * Utility function for retrieving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +getText = Sizzle.getText = function( elem ) { + var node, + ret = "", + i = 0, + nodeType = elem.nodeType; + + if ( !nodeType ) { + + // If no nodeType, this is expected to be an array + while ( ( node = elem[ i++ ] ) ) { + + // Do not traverse comment nodes + ret += getText( node ); + } + } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + + // Use textContent for elements + // innerText usage removed for consistency of new lines (jQuery #11153) + if ( typeof elem.textContent === "string" ) { + return elem.textContent; + } else { + + // Traverse its children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + + // Do not include comment or processing instruction nodes + + return ret; +}; + +Expr = Sizzle.selectors = { + + // Can be adjusted by the user + cacheLength: 50, + + createPseudo: markFunction, + + match: matchExpr, + + attrHandle: {}, + + find: {}, + + relative: { + ">": { dir: "parentNode", first: true }, + " ": { dir: "parentNode" }, + "+": { dir: "previousSibling", first: true }, + "~": { dir: "previousSibling" } + }, + + preFilter: { + "ATTR": function( match ) { + match[ 1 ] = match[ 1 ].replace( runescape, funescape ); + + // Move the given value to match[3] whether quoted or unquoted + match[ 3 ] = ( match[ 3 ] || match[ 4 ] || + match[ 5 ] || "" ).replace( runescape, funescape ); + + if ( match[ 2 ] === "~=" ) { + match[ 3 ] = " " + match[ 3 ] + " "; + } + + return match.slice( 0, 4 ); + }, + + "CHILD": function( match ) { + + /* matches from matchExpr["CHILD"] + 1 type (only|nth|...) + 2 what (child|of-type) + 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) + 4 xn-component of xn+y argument ([+-]?\d*n|) + 5 sign of xn-component + 6 x of xn-component + 7 sign of y-component + 8 y of y-component + */ + match[ 1 ] = match[ 1 ].toLowerCase(); + + if ( match[ 1 ].slice( 0, 3 ) === "nth" ) { + + // nth-* requires argument + if ( !match[ 3 ] ) { + Sizzle.error( match[ 0 ] ); + } + + // numeric x and y parameters for Expr.filter.CHILD + // remember that false/true cast respectively to 0/1 + match[ 4 ] = +( match[ 4 ] ? + match[ 5 ] + ( match[ 6 ] || 1 ) : + 2 * ( match[ 3 ] === "even" || match[ 3 ] === "odd" ) ); + match[ 5 ] = +( ( match[ 7 ] + match[ 8 ] ) || match[ 3 ] === "odd" ); + + // other types prohibit arguments + } else if ( match[ 3 ] ) { + Sizzle.error( match[ 0 ] ); + } + + return match; + }, + + "PSEUDO": function( match ) { + var excess, + unquoted = !match[ 6 ] && match[ 2 ]; + + if ( matchExpr[ "CHILD" ].test( match[ 0 ] ) ) { + return null; + } + + // Accept quoted arguments as-is + if ( match[ 3 ] ) { + match[ 2 ] = match[ 4 ] || match[ 5 ] || ""; + + // Strip excess characters from unquoted arguments + } else if ( unquoted && rpseudo.test( unquoted ) && + + // Get excess from tokenize (recursively) + ( excess = tokenize( unquoted, true ) ) && + + // advance to the next closing parenthesis + ( excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length ) ) { + + // excess is a negative index + match[ 0 ] = match[ 0 ].slice( 0, excess ); + match[ 2 ] = unquoted.slice( 0, excess ); + } + + // Return only captures needed by the pseudo filter method (type and argument) + return match.slice( 0, 3 ); + } + }, + + filter: { + + "TAG": function( nodeNameSelector ) { + var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); + return nodeNameSelector === "*" ? + function() { + return true; + } : + function( elem ) { + return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; + }; + }, + + "CLASS": function( className ) { + var pattern = classCache[ className + " " ]; + + return pattern || + ( pattern = new RegExp( "(^|" + whitespace + + ")" + className + "(" + whitespace + "|$)" ) ) && classCache( + className, function( elem ) { + return pattern.test( + typeof elem.className === "string" && elem.className || + typeof elem.getAttribute !== "undefined" && + elem.getAttribute( "class" ) || + "" + ); + } ); + }, + + "ATTR": function( name, operator, check ) { + return function( elem ) { + var result = Sizzle.attr( elem, name ); + + if ( result == null ) { + return operator === "!="; + } + if ( !operator ) { + return true; + } + + result += ""; + + /* eslint-disable max-len */ + + return operator === "=" ? result === check : + operator === "!=" ? result !== check : + operator === "^=" ? check && result.indexOf( check ) === 0 : + operator === "*=" ? check && result.indexOf( check ) > -1 : + operator === "$=" ? check && result.slice( -check.length ) === check : + operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : + operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : + false; + /* eslint-enable max-len */ + + }; + }, + + "CHILD": function( type, what, _argument, first, last ) { + var simple = type.slice( 0, 3 ) !== "nth", + forward = type.slice( -4 ) !== "last", + ofType = what === "of-type"; + + return first === 1 && last === 0 ? + + // Shortcut for :nth-*(n) + function( elem ) { + return !!elem.parentNode; + } : + + function( elem, _context, xml ) { + var cache, uniqueCache, outerCache, node, nodeIndex, start, + dir = simple !== forward ? "nextSibling" : "previousSibling", + parent = elem.parentNode, + name = ofType && elem.nodeName.toLowerCase(), + useCache = !xml && !ofType, + diff = false; + + if ( parent ) { + + // :(first|last|only)-(child|of-type) + if ( simple ) { + while ( dir ) { + node = elem; + while ( ( node = node[ dir ] ) ) { + if ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) { + + return false; + } + } + + // Reverse direction for :only-* (if we haven't yet done so) + start = dir = type === "only" && !start && "nextSibling"; + } + return true; + } + + start = [ forward ? parent.firstChild : parent.lastChild ]; + + // non-xml :nth-child(...) stores cache data on `parent` + if ( forward && useCache ) { + + // Seek `elem` from a previously-cached index + + // ...in a gzip-friendly way + node = parent; + outerCache = node[ expando ] || ( node[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + ( outerCache[ node.uniqueID ] = {} ); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex && cache[ 2 ]; + node = nodeIndex && parent.childNodes[ nodeIndex ]; + + while ( ( node = ++nodeIndex && node && node[ dir ] || + + // Fallback to seeking `elem` from the start + ( diff = nodeIndex = 0 ) || start.pop() ) ) { + + // When found, cache indexes on `parent` and break + if ( node.nodeType === 1 && ++diff && node === elem ) { + uniqueCache[ type ] = [ dirruns, nodeIndex, diff ]; + break; + } + } + + } else { + + // Use previously-cached element index if available + if ( useCache ) { + + // ...in a gzip-friendly way + node = elem; + outerCache = node[ expando ] || ( node[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + ( outerCache[ node.uniqueID ] = {} ); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex; + } + + // xml :nth-child(...) + // or :nth-last-child(...) or :nth(-last)?-of-type(...) + if ( diff === false ) { + + // Use the same loop as above to seek `elem` from the start + while ( ( node = ++nodeIndex && node && node[ dir ] || + ( diff = nodeIndex = 0 ) || start.pop() ) ) { + + if ( ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) && + ++diff ) { + + // Cache the index of each encountered element + if ( useCache ) { + outerCache = node[ expando ] || + ( node[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + ( outerCache[ node.uniqueID ] = {} ); + + uniqueCache[ type ] = [ dirruns, diff ]; + } + + if ( node === elem ) { + break; + } + } + } + } + } + + // Incorporate the offset, then check against cycle size + diff -= last; + return diff === first || ( diff % first === 0 && diff / first >= 0 ); + } + }; + }, + + "PSEUDO": function( pseudo, argument ) { + + // pseudo-class names are case-insensitive + // http://www.w3.org/TR/selectors/#pseudo-classes + // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters + // Remember that setFilters inherits from pseudos + var args, + fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || + Sizzle.error( "unsupported pseudo: " + pseudo ); + + // The user may use createPseudo to indicate that + // arguments are needed to create the filter function + // just as Sizzle does + if ( fn[ expando ] ) { + return fn( argument ); + } + + // But maintain support for old signatures + if ( fn.length > 1 ) { + args = [ pseudo, pseudo, "", argument ]; + return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? + markFunction( function( seed, matches ) { + var idx, + matched = fn( seed, argument ), + i = matched.length; + while ( i-- ) { + idx = indexOf( seed, matched[ i ] ); + seed[ idx ] = !( matches[ idx ] = matched[ i ] ); + } + } ) : + function( elem ) { + return fn( elem, 0, args ); + }; + } + + return fn; + } + }, + + pseudos: { + + // Potentially complex pseudos + "not": markFunction( function( selector ) { + + // Trim the selector passed to compile + // to avoid treating leading and trailing + // spaces as combinators + var input = [], + results = [], + matcher = compile( selector.replace( rtrim, "$1" ) ); + + return matcher[ expando ] ? + markFunction( function( seed, matches, _context, xml ) { + var elem, + unmatched = matcher( seed, null, xml, [] ), + i = seed.length; + + // Match elements unmatched by `matcher` + while ( i-- ) { + if ( ( elem = unmatched[ i ] ) ) { + seed[ i ] = !( matches[ i ] = elem ); + } + } + } ) : + function( elem, _context, xml ) { + input[ 0 ] = elem; + matcher( input, null, xml, results ); + + // Don't keep the element (issue #299) + input[ 0 ] = null; + return !results.pop(); + }; + } ), + + "has": markFunction( function( selector ) { + return function( elem ) { + return Sizzle( selector, elem ).length > 0; + }; + } ), + + "contains": markFunction( function( text ) { + text = text.replace( runescape, funescape ); + return function( elem ) { + return ( elem.textContent || getText( elem ) ).indexOf( text ) > -1; + }; + } ), + + // "Whether an element is represented by a :lang() selector + // is based solely on the element's language value + // being equal to the identifier C, + // or beginning with the identifier C immediately followed by "-". + // The matching of C against the element's language value is performed case-insensitively. + // The identifier C does not have to be a valid language name." + // http://www.w3.org/TR/selectors/#lang-pseudo + "lang": markFunction( function( lang ) { + + // lang value must be a valid identifier + if ( !ridentifier.test( lang || "" ) ) { + Sizzle.error( "unsupported lang: " + lang ); + } + lang = lang.replace( runescape, funescape ).toLowerCase(); + return function( elem ) { + var elemLang; + do { + if ( ( elemLang = documentIsHTML ? + elem.lang : + elem.getAttribute( "xml:lang" ) || elem.getAttribute( "lang" ) ) ) { + + elemLang = elemLang.toLowerCase(); + return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; + } + } while ( ( elem = elem.parentNode ) && elem.nodeType === 1 ); + return false; + }; + } ), + + // Miscellaneous + "target": function( elem ) { + var hash = window.location && window.location.hash; + return hash && hash.slice( 1 ) === elem.id; + }, + + "root": function( elem ) { + return elem === docElem; + }, + + "focus": function( elem ) { + return elem === document.activeElement && + ( !document.hasFocus || document.hasFocus() ) && + !!( elem.type || elem.href || ~elem.tabIndex ); + }, + + // Boolean properties + "enabled": createDisabledPseudo( false ), + "disabled": createDisabledPseudo( true ), + + "checked": function( elem ) { + + // In CSS3, :checked should return both checked and selected elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + var nodeName = elem.nodeName.toLowerCase(); + return ( nodeName === "input" && !!elem.checked ) || + ( nodeName === "option" && !!elem.selected ); + }, + + "selected": function( elem ) { + + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + // eslint-disable-next-line no-unused-expressions + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + // Contents + "empty": function( elem ) { + + // http://www.w3.org/TR/selectors/#empty-pseudo + // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), + // but not by others (comment: 8; processing instruction: 7; etc.) + // nodeType < 6 works because attributes (2) do not appear as children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + if ( elem.nodeType < 6 ) { + return false; + } + } + return true; + }, + + "parent": function( elem ) { + return !Expr.pseudos[ "empty" ]( elem ); + }, + + // Element/input types + "header": function( elem ) { + return rheader.test( elem.nodeName ); + }, + + "input": function( elem ) { + return rinputs.test( elem.nodeName ); + }, + + "button": function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === "button" || name === "button"; + }, + + "text": function( elem ) { + var attr; + return elem.nodeName.toLowerCase() === "input" && + elem.type === "text" && + + // Support: IE<8 + // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" + ( ( attr = elem.getAttribute( "type" ) ) == null || + attr.toLowerCase() === "text" ); + }, + + // Position-in-collection + "first": createPositionalPseudo( function() { + return [ 0 ]; + } ), + + "last": createPositionalPseudo( function( _matchIndexes, length ) { + return [ length - 1 ]; + } ), + + "eq": createPositionalPseudo( function( _matchIndexes, length, argument ) { + return [ argument < 0 ? argument + length : argument ]; + } ), + + "even": createPositionalPseudo( function( matchIndexes, length ) { + var i = 0; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + "odd": createPositionalPseudo( function( matchIndexes, length ) { + var i = 1; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + "lt": createPositionalPseudo( function( matchIndexes, length, argument ) { + var i = argument < 0 ? + argument + length : + argument > length ? + length : + argument; + for ( ; --i >= 0; ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + "gt": createPositionalPseudo( function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; ++i < length; ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ) + } +}; + +Expr.pseudos[ "nth" ] = Expr.pseudos[ "eq" ]; + +// Add button/input type pseudos +for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { + Expr.pseudos[ i ] = createInputPseudo( i ); +} +for ( i in { submit: true, reset: true } ) { + Expr.pseudos[ i ] = createButtonPseudo( i ); +} + +// Easy API for creating new setFilters +function setFilters() {} +setFilters.prototype = Expr.filters = Expr.pseudos; +Expr.setFilters = new setFilters(); + +tokenize = Sizzle.tokenize = function( selector, parseOnly ) { + var matched, match, tokens, type, + soFar, groups, preFilters, + cached = tokenCache[ selector + " " ]; + + if ( cached ) { + return parseOnly ? 0 : cached.slice( 0 ); + } + + soFar = selector; + groups = []; + preFilters = Expr.preFilter; + + while ( soFar ) { + + // Comma and first run + if ( !matched || ( match = rcomma.exec( soFar ) ) ) { + if ( match ) { + + // Don't consume trailing commas as valid + soFar = soFar.slice( match[ 0 ].length ) || soFar; + } + groups.push( ( tokens = [] ) ); + } + + matched = false; + + // Combinators + if ( ( match = rcombinators.exec( soFar ) ) ) { + matched = match.shift(); + tokens.push( { + value: matched, + + // Cast descendant combinators to space + type: match[ 0 ].replace( rtrim, " " ) + } ); + soFar = soFar.slice( matched.length ); + } + + // Filters + for ( type in Expr.filter ) { + if ( ( match = matchExpr[ type ].exec( soFar ) ) && ( !preFilters[ type ] || + ( match = preFilters[ type ]( match ) ) ) ) { + matched = match.shift(); + tokens.push( { + value: matched, + type: type, + matches: match + } ); + soFar = soFar.slice( matched.length ); + } + } + + if ( !matched ) { + break; + } + } + + // Return the length of the invalid excess + // if we're just parsing + // Otherwise, throw an error or return tokens + return parseOnly ? + soFar.length : + soFar ? + Sizzle.error( selector ) : + + // Cache the tokens + tokenCache( selector, groups ).slice( 0 ); +}; + +function toSelector( tokens ) { + var i = 0, + len = tokens.length, + selector = ""; + for ( ; i < len; i++ ) { + selector += tokens[ i ].value; + } + return selector; +} + +function addCombinator( matcher, combinator, base ) { + var dir = combinator.dir, + skip = combinator.next, + key = skip || dir, + checkNonElements = base && key === "parentNode", + doneName = done++; + + return combinator.first ? + + // Check against closest ancestor/preceding element + function( elem, context, xml ) { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + return matcher( elem, context, xml ); + } + } + return false; + } : + + // Check against all ancestor/preceding elements + function( elem, context, xml ) { + var oldCache, uniqueCache, outerCache, + newCache = [ dirruns, doneName ]; + + // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching + if ( xml ) { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + if ( matcher( elem, context, xml ) ) { + return true; + } + } + } + } else { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + outerCache = elem[ expando ] || ( elem[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ elem.uniqueID ] || + ( outerCache[ elem.uniqueID ] = {} ); + + if ( skip && skip === elem.nodeName.toLowerCase() ) { + elem = elem[ dir ] || elem; + } else if ( ( oldCache = uniqueCache[ key ] ) && + oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { + + // Assign to newCache so results back-propagate to previous elements + return ( newCache[ 2 ] = oldCache[ 2 ] ); + } else { + + // Reuse newcache so results back-propagate to previous elements + uniqueCache[ key ] = newCache; + + // A match means we're done; a fail means we have to keep checking + if ( ( newCache[ 2 ] = matcher( elem, context, xml ) ) ) { + return true; + } + } + } + } + } + return false; + }; +} + +function elementMatcher( matchers ) { + return matchers.length > 1 ? + function( elem, context, xml ) { + var i = matchers.length; + while ( i-- ) { + if ( !matchers[ i ]( elem, context, xml ) ) { + return false; + } + } + return true; + } : + matchers[ 0 ]; +} + +function multipleContexts( selector, contexts, results ) { + var i = 0, + len = contexts.length; + for ( ; i < len; i++ ) { + Sizzle( selector, contexts[ i ], results ); + } + return results; +} + +function condense( unmatched, map, filter, context, xml ) { + var elem, + newUnmatched = [], + i = 0, + len = unmatched.length, + mapped = map != null; + + for ( ; i < len; i++ ) { + if ( ( elem = unmatched[ i ] ) ) { + if ( !filter || filter( elem, context, xml ) ) { + newUnmatched.push( elem ); + if ( mapped ) { + map.push( i ); + } + } + } + } + + return newUnmatched; +} + +function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { + if ( postFilter && !postFilter[ expando ] ) { + postFilter = setMatcher( postFilter ); + } + if ( postFinder && !postFinder[ expando ] ) { + postFinder = setMatcher( postFinder, postSelector ); + } + return markFunction( function( seed, results, context, xml ) { + var temp, i, elem, + preMap = [], + postMap = [], + preexisting = results.length, + + // Get initial elements from seed or context + elems = seed || multipleContexts( + selector || "*", + context.nodeType ? [ context ] : context, + [] + ), + + // Prefilter to get matcher input, preserving a map for seed-results synchronization + matcherIn = preFilter && ( seed || !selector ) ? + condense( elems, preMap, preFilter, context, xml ) : + elems, + + matcherOut = matcher ? + + // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, + postFinder || ( seed ? preFilter : preexisting || postFilter ) ? + + // ...intermediate processing is necessary + [] : + + // ...otherwise use results directly + results : + matcherIn; + + // Find primary matches + if ( matcher ) { + matcher( matcherIn, matcherOut, context, xml ); + } + + // Apply postFilter + if ( postFilter ) { + temp = condense( matcherOut, postMap ); + postFilter( temp, [], context, xml ); + + // Un-match failing elements by moving them back to matcherIn + i = temp.length; + while ( i-- ) { + if ( ( elem = temp[ i ] ) ) { + matcherOut[ postMap[ i ] ] = !( matcherIn[ postMap[ i ] ] = elem ); + } + } + } + + if ( seed ) { + if ( postFinder || preFilter ) { + if ( postFinder ) { + + // Get the final matcherOut by condensing this intermediate into postFinder contexts + temp = []; + i = matcherOut.length; + while ( i-- ) { + if ( ( elem = matcherOut[ i ] ) ) { + + // Restore matcherIn since elem is not yet a final match + temp.push( ( matcherIn[ i ] = elem ) ); + } + } + postFinder( null, ( matcherOut = [] ), temp, xml ); + } + + // Move matched elements from seed to results to keep them synchronized + i = matcherOut.length; + while ( i-- ) { + if ( ( elem = matcherOut[ i ] ) && + ( temp = postFinder ? indexOf( seed, elem ) : preMap[ i ] ) > -1 ) { + + seed[ temp ] = !( results[ temp ] = elem ); + } + } + } + + // Add elements to results, through postFinder if defined + } else { + matcherOut = condense( + matcherOut === results ? + matcherOut.splice( preexisting, matcherOut.length ) : + matcherOut + ); + if ( postFinder ) { + postFinder( null, results, matcherOut, xml ); + } else { + push.apply( results, matcherOut ); + } + } + } ); +} + +function matcherFromTokens( tokens ) { + var checkContext, matcher, j, + len = tokens.length, + leadingRelative = Expr.relative[ tokens[ 0 ].type ], + implicitRelative = leadingRelative || Expr.relative[ " " ], + i = leadingRelative ? 1 : 0, + + // The foundational matcher ensures that elements are reachable from top-level context(s) + matchContext = addCombinator( function( elem ) { + return elem === checkContext; + }, implicitRelative, true ), + matchAnyContext = addCombinator( function( elem ) { + return indexOf( checkContext, elem ) > -1; + }, implicitRelative, true ), + matchers = [ function( elem, context, xml ) { + var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( + ( checkContext = context ).nodeType ? + matchContext( elem, context, xml ) : + matchAnyContext( elem, context, xml ) ); + + // Avoid hanging onto element (issue #299) + checkContext = null; + return ret; + } ]; + + for ( ; i < len; i++ ) { + if ( ( matcher = Expr.relative[ tokens[ i ].type ] ) ) { + matchers = [ addCombinator( elementMatcher( matchers ), matcher ) ]; + } else { + matcher = Expr.filter[ tokens[ i ].type ].apply( null, tokens[ i ].matches ); + + // Return special upon seeing a positional matcher + if ( matcher[ expando ] ) { + + // Find the next relative operator (if any) for proper handling + j = ++i; + for ( ; j < len; j++ ) { + if ( Expr.relative[ tokens[ j ].type ] ) { + break; + } + } + return setMatcher( + i > 1 && elementMatcher( matchers ), + i > 1 && toSelector( + + // If the preceding token was a descendant combinator, insert an implicit any-element `*` + tokens + .slice( 0, i - 1 ) + .concat( { value: tokens[ i - 2 ].type === " " ? "*" : "" } ) + ).replace( rtrim, "$1" ), + matcher, + i < j && matcherFromTokens( tokens.slice( i, j ) ), + j < len && matcherFromTokens( ( tokens = tokens.slice( j ) ) ), + j < len && toSelector( tokens ) + ); + } + matchers.push( matcher ); + } + } + + return elementMatcher( matchers ); +} + +function matcherFromGroupMatchers( elementMatchers, setMatchers ) { + var bySet = setMatchers.length > 0, + byElement = elementMatchers.length > 0, + superMatcher = function( seed, context, xml, results, outermost ) { + var elem, j, matcher, + matchedCount = 0, + i = "0", + unmatched = seed && [], + setMatched = [], + contextBackup = outermostContext, + + // We must always have either seed elements or outermost context + elems = seed || byElement && Expr.find[ "TAG" ]( "*", outermost ), + + // Use integer dirruns iff this is the outermost matcher + dirrunsUnique = ( dirruns += contextBackup == null ? 1 : Math.random() || 0.1 ), + len = elems.length; + + if ( outermost ) { + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + outermostContext = context == document || context || outermost; + } + + // Add elements passing elementMatchers directly to results + // Support: IE<9, Safari + // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id + for ( ; i !== len && ( elem = elems[ i ] ) != null; i++ ) { + if ( byElement && elem ) { + j = 0; + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( !context && elem.ownerDocument != document ) { + setDocument( elem ); + xml = !documentIsHTML; + } + while ( ( matcher = elementMatchers[ j++ ] ) ) { + if ( matcher( elem, context || document, xml ) ) { + results.push( elem ); + break; + } + } + if ( outermost ) { + dirruns = dirrunsUnique; + } + } + + // Track unmatched elements for set filters + if ( bySet ) { + + // They will have gone through all possible matchers + if ( ( elem = !matcher && elem ) ) { + matchedCount--; + } + + // Lengthen the array for every element, matched or not + if ( seed ) { + unmatched.push( elem ); + } + } + } + + // `i` is now the count of elements visited above, and adding it to `matchedCount` + // makes the latter nonnegative. + matchedCount += i; + + // Apply set filters to unmatched elements + // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` + // equals `i`), unless we didn't visit _any_ elements in the above loop because we have + // no element matchers and no seed. + // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that + // case, which will result in a "00" `matchedCount` that differs from `i` but is also + // numerically zero. + if ( bySet && i !== matchedCount ) { + j = 0; + while ( ( matcher = setMatchers[ j++ ] ) ) { + matcher( unmatched, setMatched, context, xml ); + } + + if ( seed ) { + + // Reintegrate element matches to eliminate the need for sorting + if ( matchedCount > 0 ) { + while ( i-- ) { + if ( !( unmatched[ i ] || setMatched[ i ] ) ) { + setMatched[ i ] = pop.call( results ); + } + } + } + + // Discard index placeholder values to get only actual matches + setMatched = condense( setMatched ); + } + + // Add matches to results + push.apply( results, setMatched ); + + // Seedless set matches succeeding multiple successful matchers stipulate sorting + if ( outermost && !seed && setMatched.length > 0 && + ( matchedCount + setMatchers.length ) > 1 ) { + + Sizzle.uniqueSort( results ); + } + } + + // Override manipulation of globals by nested matchers + if ( outermost ) { + dirruns = dirrunsUnique; + outermostContext = contextBackup; + } + + return unmatched; + }; + + return bySet ? + markFunction( superMatcher ) : + superMatcher; +} + +compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { + var i, + setMatchers = [], + elementMatchers = [], + cached = compilerCache[ selector + " " ]; + + if ( !cached ) { + + // Generate a function of recursive functions that can be used to check each element + if ( !match ) { + match = tokenize( selector ); + } + i = match.length; + while ( i-- ) { + cached = matcherFromTokens( match[ i ] ); + if ( cached[ expando ] ) { + setMatchers.push( cached ); + } else { + elementMatchers.push( cached ); + } + } + + // Cache the compiled function + cached = compilerCache( + selector, + matcherFromGroupMatchers( elementMatchers, setMatchers ) + ); + + // Save selector and tokenization + cached.selector = selector; + } + return cached; +}; + +/** + * A low-level selection function that works with Sizzle's compiled + * selector functions + * @param {String|Function} selector A selector or a pre-compiled + * selector function built with Sizzle.compile + * @param {Element} context + * @param {Array} [results] + * @param {Array} [seed] A set of elements to match against + */ +select = Sizzle.select = function( selector, context, results, seed ) { + var i, tokens, token, type, find, + compiled = typeof selector === "function" && selector, + match = !seed && tokenize( ( selector = compiled.selector || selector ) ); + + results = results || []; + + // Try to minimize operations if there is only one selector in the list and no seed + // (the latter of which guarantees us context) + if ( match.length === 1 ) { + + // Reduce context if the leading compound selector is an ID + tokens = match[ 0 ] = match[ 0 ].slice( 0 ); + if ( tokens.length > 2 && ( token = tokens[ 0 ] ).type === "ID" && + context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[ 1 ].type ] ) { + + context = ( Expr.find[ "ID" ]( token.matches[ 0 ] + .replace( runescape, funescape ), context ) || [] )[ 0 ]; + if ( !context ) { + return results; + + // Precompiled matchers will still verify ancestry, so step up a level + } else if ( compiled ) { + context = context.parentNode; + } + + selector = selector.slice( tokens.shift().value.length ); + } + + // Fetch a seed set for right-to-left matching + i = matchExpr[ "needsContext" ].test( selector ) ? 0 : tokens.length; + while ( i-- ) { + token = tokens[ i ]; + + // Abort if we hit a combinator + if ( Expr.relative[ ( type = token.type ) ] ) { + break; + } + if ( ( find = Expr.find[ type ] ) ) { + + // Search, expanding context for leading sibling combinators + if ( ( seed = find( + token.matches[ 0 ].replace( runescape, funescape ), + rsibling.test( tokens[ 0 ].type ) && testContext( context.parentNode ) || + context + ) ) ) { + + // If seed is empty or no tokens remain, we can return early + tokens.splice( i, 1 ); + selector = seed.length && toSelector( tokens ); + if ( !selector ) { + push.apply( results, seed ); + return results; + } + + break; + } + } + } + } + + // Compile and execute a filtering function if one is not provided + // Provide `match` to avoid retokenization if we modified the selector above + ( compiled || compile( selector, match ) )( + seed, + context, + !documentIsHTML, + results, + !context || rsibling.test( selector ) && testContext( context.parentNode ) || context + ); + return results; +}; + +// One-time assignments + +// Sort stability +support.sortStable = expando.split( "" ).sort( sortOrder ).join( "" ) === expando; + +// Support: Chrome 14-35+ +// Always assume duplicates if they aren't passed to the comparison function +support.detectDuplicates = !!hasDuplicate; + +// Initialize against the default document +setDocument(); + +// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) +// Detached nodes confoundingly follow *each other* +support.sortDetached = assert( function( el ) { + + // Should return 1, but returns 4 (following) + return el.compareDocumentPosition( document.createElement( "fieldset" ) ) & 1; +} ); + +// Support: IE<8 +// Prevent attribute/property "interpolation" +// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx +if ( !assert( function( el ) { + el.innerHTML = ""; + return el.firstChild.getAttribute( "href" ) === "#"; +} ) ) { + addHandle( "type|href|height|width", function( elem, name, isXML ) { + if ( !isXML ) { + return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); + } + } ); +} + +// Support: IE<9 +// Use defaultValue in place of getAttribute("value") +if ( !support.attributes || !assert( function( el ) { + el.innerHTML = ""; + el.firstChild.setAttribute( "value", "" ); + return el.firstChild.getAttribute( "value" ) === ""; +} ) ) { + addHandle( "value", function( elem, _name, isXML ) { + if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { + return elem.defaultValue; + } + } ); +} + +// Support: IE<9 +// Use getAttributeNode to fetch booleans when getAttribute lies +if ( !assert( function( el ) { + return el.getAttribute( "disabled" ) == null; +} ) ) { + addHandle( booleans, function( elem, name, isXML ) { + var val; + if ( !isXML ) { + return elem[ name ] === true ? name.toLowerCase() : + ( val = elem.getAttributeNode( name ) ) && val.specified ? + val.value : + null; + } + } ); +} + +return Sizzle; + +} )( window ); + + + +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; + +// Deprecated +jQuery.expr[ ":" ] = jQuery.expr.pseudos; +jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; +jQuery.escapeSelector = Sizzle.escape; + + + + +var dir = function( elem, dir, until ) { + var matched = [], + truncate = until !== undefined; + + while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) { + if ( elem.nodeType === 1 ) { + if ( truncate && jQuery( elem ).is( until ) ) { + break; + } + matched.push( elem ); + } + } + return matched; +}; + + +var siblings = function( n, elem ) { + var matched = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + matched.push( n ); + } + } + + return matched; +}; + + +var rneedsContext = jQuery.expr.match.needsContext; + + + +function nodeName( elem, name ) { + + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + +} +var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); + + + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, not ) { + if ( isFunction( qualifier ) ) { + return jQuery.grep( elements, function( elem, i ) { + return !!qualifier.call( elem, i, elem ) !== not; + } ); + } + + // Single element + if ( qualifier.nodeType ) { + return jQuery.grep( elements, function( elem ) { + return ( elem === qualifier ) !== not; + } ); + } + + // Arraylike of elements (jQuery, arguments, Array) + if ( typeof qualifier !== "string" ) { + return jQuery.grep( elements, function( elem ) { + return ( indexOf.call( qualifier, elem ) > -1 ) !== not; + } ); + } + + // Filtered directly for both simple and complex selectors + return jQuery.filter( qualifier, elements, not ); +} + +jQuery.filter = function( expr, elems, not ) { + var elem = elems[ 0 ]; + + if ( not ) { + expr = ":not(" + expr + ")"; + } + + if ( elems.length === 1 && elem.nodeType === 1 ) { + return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : []; + } + + return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { + return elem.nodeType === 1; + } ) ); +}; + +jQuery.fn.extend( { + find: function( selector ) { + var i, ret, + len = this.length, + self = this; + + if ( typeof selector !== "string" ) { + return this.pushStack( jQuery( selector ).filter( function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + } ) ); + } + + ret = this.pushStack( [] ); + + for ( i = 0; i < len; i++ ) { + jQuery.find( selector, self[ i ], ret ); + } + + return len > 1 ? jQuery.uniqueSort( ret ) : ret; + }, + filter: function( selector ) { + return this.pushStack( winnow( this, selector || [], false ) ); + }, + not: function( selector ) { + return this.pushStack( winnow( this, selector || [], true ) ); + }, + is: function( selector ) { + return !!winnow( + this, + + // If this is a positional/relative selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + typeof selector === "string" && rneedsContext.test( selector ) ? + jQuery( selector ) : + selector || [], + false + ).length; + } +} ); + + +// Initialize a jQuery object + + +// A central reference to the root jQuery(document) +var rootjQuery, + + // A simple way to check for HTML strings + // Prioritize #id over to avoid XSS via location.hash (#9521) + // Strict HTML recognition (#11290: must start with <) + // Shortcut simple #id case for speed + rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, + + init = jQuery.fn.init = function( selector, context, root ) { + var match, elem; + + // HANDLE: $(""), $(null), $(undefined), $(false) + if ( !selector ) { + return this; + } + + // Method init() accepts an alternate rootjQuery + // so migrate can support jQuery.sub (gh-2101) + root = root || rootjQuery; + + // Handle HTML strings + if ( typeof selector === "string" ) { + if ( selector[ 0 ] === "<" && + selector[ selector.length - 1 ] === ">" && + selector.length >= 3 ) { + + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = rquickExpr.exec( selector ); + } + + // Match html or make sure no context is specified for #id + if ( match && ( match[ 1 ] || !context ) ) { + + // HANDLE: $(html) -> $(array) + if ( match[ 1 ] ) { + context = context instanceof jQuery ? context[ 0 ] : context; + + // Option to run scripts is true for back-compat + // Intentionally let the error be thrown if parseHTML is not present + jQuery.merge( this, jQuery.parseHTML( + match[ 1 ], + context && context.nodeType ? context.ownerDocument || context : document, + true + ) ); + + // HANDLE: $(html, props) + if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) { + for ( match in context ) { + + // Properties of context are called as methods if possible + if ( isFunction( this[ match ] ) ) { + this[ match ]( context[ match ] ); + + // ...and otherwise set as attributes + } else { + this.attr( match, context[ match ] ); + } + } + } + + return this; + + // HANDLE: $(#id) + } else { + elem = document.getElementById( match[ 2 ] ); + + if ( elem ) { + + // Inject the element directly into the jQuery object + this[ 0 ] = elem; + this.length = 1; + } + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || root ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(DOMElement) + } else if ( selector.nodeType ) { + this[ 0 ] = selector; + this.length = 1; + return this; + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( isFunction( selector ) ) { + return root.ready !== undefined ? + root.ready( selector ) : + + // Execute immediately if ready is not present + selector( jQuery ); + } + + return jQuery.makeArray( selector, this ); + }; + +// Give the init function the jQuery prototype for later instantiation +init.prototype = jQuery.fn; + +// Initialize central reference +rootjQuery = jQuery( document ); + + +var rparentsprev = /^(?:parents|prev(?:Until|All))/, + + // Methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend( { + has: function( target ) { + var targets = jQuery( target, this ), + l = targets.length; + + return this.filter( function() { + var i = 0; + for ( ; i < l; i++ ) { + if ( jQuery.contains( this, targets[ i ] ) ) { + return true; + } + } + } ); + }, + + closest: function( selectors, context ) { + var cur, + i = 0, + l = this.length, + matched = [], + targets = typeof selectors !== "string" && jQuery( selectors ); + + // Positional selectors never match, since there's no _selection_ context + if ( !rneedsContext.test( selectors ) ) { + for ( ; i < l; i++ ) { + for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { + + // Always skip document fragments + if ( cur.nodeType < 11 && ( targets ? + targets.index( cur ) > -1 : + + // Don't pass non-elements to Sizzle + cur.nodeType === 1 && + jQuery.find.matchesSelector( cur, selectors ) ) ) { + + matched.push( cur ); + break; + } + } + } + } + + return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched ); + }, + + // Determine the position of an element within the set + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; + } + + // Index in selector + if ( typeof elem === "string" ) { + return indexOf.call( jQuery( elem ), this[ 0 ] ); + } + + // Locate the position of the desired element + return indexOf.call( this, + + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[ 0 ] : elem + ); + }, + + add: function( selector, context ) { + return this.pushStack( + jQuery.uniqueSort( + jQuery.merge( this.get(), jQuery( selector, context ) ) + ) + ); + }, + + addBack: function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter( selector ) + ); + } +} ); + +function sibling( cur, dir ) { + while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {} + return cur; +} + +jQuery.each( { + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, _i, until ) { + return dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return sibling( elem, "nextSibling" ); + }, + prev: function( elem ) { + return sibling( elem, "previousSibling" ); + }, + nextAll: function( elem ) { + return dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, _i, until ) { + return dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, _i, until ) { + return dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return siblings( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return siblings( elem.firstChild ); + }, + contents: function( elem ) { + if ( elem.contentDocument != null && + + // Support: IE 11+ + // elements with no `data` attribute has an object + // `contentDocument` with a `null` prototype. + getProto( elem.contentDocument ) ) { + + return elem.contentDocument; + } + + // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only + // Treat the template element as a regular one in browsers that + // don't support it. + if ( nodeName( elem, "template" ) ) { + elem = elem.content || elem; + } + + return jQuery.merge( [], elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var matched = jQuery.map( this, fn, until ); + + if ( name.slice( -5 ) !== "Until" ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + matched = jQuery.filter( selector, matched ); + } + + if ( this.length > 1 ) { + + // Remove duplicates + if ( !guaranteedUnique[ name ] ) { + jQuery.uniqueSort( matched ); + } + + // Reverse order for parents* and prev-derivatives + if ( rparentsprev.test( name ) ) { + matched.reverse(); + } + } + + return this.pushStack( matched ); + }; +} ); +var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g ); + + + +// Convert String-formatted options into Object-formatted ones +function createOptions( options ) { + var object = {}; + jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) { + object[ flag ] = true; + } ); + return object; +} + +/* + * Create a callback list using the following parameters: + * + * options: an optional list of space-separated options that will change how + * the callback list behaves or a more traditional option object + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible options: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( options ) { + + // Convert options from String-formatted to Object-formatted if needed + // (we check in cache first) + options = typeof options === "string" ? + createOptions( options ) : + jQuery.extend( {}, options ); + + var // Flag to know if list is currently firing + firing, + + // Last fire value for non-forgettable lists + memory, + + // Flag to know if list was already fired + fired, + + // Flag to prevent firing + locked, + + // Actual callback list + list = [], + + // Queue of execution data for repeatable lists + queue = [], + + // Index of currently firing callback (modified by add/remove as needed) + firingIndex = -1, + + // Fire callbacks + fire = function() { + + // Enforce single-firing + locked = locked || options.once; + + // Execute callbacks for all pending executions, + // respecting firingIndex overrides and runtime changes + fired = firing = true; + for ( ; queue.length; firingIndex = -1 ) { + memory = queue.shift(); + while ( ++firingIndex < list.length ) { + + // Run callback and check for early termination + if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && + options.stopOnFalse ) { + + // Jump to end and forget the data so .add doesn't re-fire + firingIndex = list.length; + memory = false; + } + } + } + + // Forget the data if we're done with it + if ( !options.memory ) { + memory = false; + } + + firing = false; + + // Clean up if we're done firing for good + if ( locked ) { + + // Keep an empty list if we have data for future add calls + if ( memory ) { + list = []; + + // Otherwise, this object is spent + } else { + list = ""; + } + } + }, + + // Actual Callbacks object + self = { + + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + + // If we have memory from a past run, we should fire after adding + if ( memory && !firing ) { + firingIndex = list.length - 1; + queue.push( memory ); + } + + ( function add( args ) { + jQuery.each( args, function( _, arg ) { + if ( isFunction( arg ) ) { + if ( !options.unique || !self.has( arg ) ) { + list.push( arg ); + } + } else if ( arg && arg.length && toType( arg ) !== "string" ) { + + // Inspect recursively + add( arg ); + } + } ); + } )( arguments ); + + if ( memory && !firing ) { + fire(); + } + } + return this; + }, + + // Remove a callback from the list + remove: function() { + jQuery.each( arguments, function( _, arg ) { + var index; + while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { + list.splice( index, 1 ); + + // Handle firing indexes + if ( index <= firingIndex ) { + firingIndex--; + } + } + } ); + return this; + }, + + // Check if a given callback is in the list. + // If no argument is given, return whether or not list has callbacks attached. + has: function( fn ) { + return fn ? + jQuery.inArray( fn, list ) > -1 : + list.length > 0; + }, + + // Remove all callbacks from the list + empty: function() { + if ( list ) { + list = []; + } + return this; + }, + + // Disable .fire and .add + // Abort any current/pending executions + // Clear all callbacks and values + disable: function() { + locked = queue = []; + list = memory = ""; + return this; + }, + disabled: function() { + return !list; + }, + + // Disable .fire + // Also disable .add unless we have memory (since it would have no effect) + // Abort any pending executions + lock: function() { + locked = queue = []; + if ( !memory && !firing ) { + list = memory = ""; + } + return this; + }, + locked: function() { + return !!locked; + }, + + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + if ( !locked ) { + args = args || []; + args = [ context, args.slice ? args.slice() : args ]; + queue.push( args ); + if ( !firing ) { + fire(); + } + } + return this; + }, + + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; + + +function Identity( v ) { + return v; +} +function Thrower( ex ) { + throw ex; +} + +function adoptValue( value, resolve, reject, noValue ) { + var method; + + try { + + // Check for promise aspect first to privilege synchronous behavior + if ( value && isFunction( ( method = value.promise ) ) ) { + method.call( value ).done( resolve ).fail( reject ); + + // Other thenables + } else if ( value && isFunction( ( method = value.then ) ) ) { + method.call( value, resolve, reject ); + + // Other non-thenables + } else { + + // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer: + // * false: [ value ].slice( 0 ) => resolve( value ) + // * true: [ value ].slice( 1 ) => resolve() + resolve.apply( undefined, [ value ].slice( noValue ) ); + } + + // For Promises/A+, convert exceptions into rejections + // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in + // Deferred#then to conditionally suppress rejection. + } catch ( value ) { + + // Support: Android 4.0 only + // Strict mode functions invoked without .call/.apply get global-object context + reject.apply( undefined, [ value ] ); + } +} + +jQuery.extend( { + + Deferred: function( func ) { + var tuples = [ + + // action, add listener, callbacks, + // ... .then handlers, argument index, [final state] + [ "notify", "progress", jQuery.Callbacks( "memory" ), + jQuery.Callbacks( "memory" ), 2 ], + [ "resolve", "done", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 0, "resolved" ], + [ "reject", "fail", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 1, "rejected" ] + ], + state = "pending", + promise = { + state: function() { + return state; + }, + always: function() { + deferred.done( arguments ).fail( arguments ); + return this; + }, + "catch": function( fn ) { + return promise.then( null, fn ); + }, + + // Keep pipe for back-compat + pipe: function( /* fnDone, fnFail, fnProgress */ ) { + var fns = arguments; + + return jQuery.Deferred( function( newDefer ) { + jQuery.each( tuples, function( _i, tuple ) { + + // Map tuples (progress, done, fail) to arguments (done, fail, progress) + var fn = isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ]; + + // deferred.progress(function() { bind to newDefer or newDefer.notify }) + // deferred.done(function() { bind to newDefer or newDefer.resolve }) + // deferred.fail(function() { bind to newDefer or newDefer.reject }) + deferred[ tuple[ 1 ] ]( function() { + var returned = fn && fn.apply( this, arguments ); + if ( returned && isFunction( returned.promise ) ) { + returned.promise() + .progress( newDefer.notify ) + .done( newDefer.resolve ) + .fail( newDefer.reject ); + } else { + newDefer[ tuple[ 0 ] + "With" ]( + this, + fn ? [ returned ] : arguments + ); + } + } ); + } ); + fns = null; + } ).promise(); + }, + then: function( onFulfilled, onRejected, onProgress ) { + var maxDepth = 0; + function resolve( depth, deferred, handler, special ) { + return function() { + var that = this, + args = arguments, + mightThrow = function() { + var returned, then; + + // Support: Promises/A+ section 2.3.3.3.3 + // https://promisesaplus.com/#point-59 + // Ignore double-resolution attempts + if ( depth < maxDepth ) { + return; + } + + returned = handler.apply( that, args ); + + // Support: Promises/A+ section 2.3.1 + // https://promisesaplus.com/#point-48 + if ( returned === deferred.promise() ) { + throw new TypeError( "Thenable self-resolution" ); + } + + // Support: Promises/A+ sections 2.3.3.1, 3.5 + // https://promisesaplus.com/#point-54 + // https://promisesaplus.com/#point-75 + // Retrieve `then` only once + then = returned && + + // Support: Promises/A+ section 2.3.4 + // https://promisesaplus.com/#point-64 + // Only check objects and functions for thenability + ( typeof returned === "object" || + typeof returned === "function" ) && + returned.then; + + // Handle a returned thenable + if ( isFunction( then ) ) { + + // Special processors (notify) just wait for resolution + if ( special ) { + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ) + ); + + // Normal processors (resolve) also hook into progress + } else { + + // ...and disregard older resolution values + maxDepth++; + + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ), + resolve( maxDepth, deferred, Identity, + deferred.notifyWith ) + ); + } + + // Handle all other returned values + } else { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Identity ) { + that = undefined; + args = [ returned ]; + } + + // Process the value(s) + // Default process is resolve + ( special || deferred.resolveWith )( that, args ); + } + }, + + // Only normal processors (resolve) catch and reject exceptions + process = special ? + mightThrow : + function() { + try { + mightThrow(); + } catch ( e ) { + + if ( jQuery.Deferred.exceptionHook ) { + jQuery.Deferred.exceptionHook( e, + process.stackTrace ); + } + + // Support: Promises/A+ section 2.3.3.3.4.1 + // https://promisesaplus.com/#point-61 + // Ignore post-resolution exceptions + if ( depth + 1 >= maxDepth ) { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Thrower ) { + that = undefined; + args = [ e ]; + } + + deferred.rejectWith( that, args ); + } + } + }; + + // Support: Promises/A+ section 2.3.3.3.1 + // https://promisesaplus.com/#point-57 + // Re-resolve promises immediately to dodge false rejection from + // subsequent errors + if ( depth ) { + process(); + } else { + + // Call an optional hook to record the stack, in case of exception + // since it's otherwise lost when execution goes async + if ( jQuery.Deferred.getStackHook ) { + process.stackTrace = jQuery.Deferred.getStackHook(); + } + window.setTimeout( process ); + } + }; + } + + return jQuery.Deferred( function( newDefer ) { + + // progress_handlers.add( ... ) + tuples[ 0 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onProgress ) ? + onProgress : + Identity, + newDefer.notifyWith + ) + ); + + // fulfilled_handlers.add( ... ) + tuples[ 1 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onFulfilled ) ? + onFulfilled : + Identity + ) + ); + + // rejected_handlers.add( ... ) + tuples[ 2 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onRejected ) ? + onRejected : + Thrower + ) + ); + } ).promise(); + }, + + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + return obj != null ? jQuery.extend( obj, promise ) : promise; + } + }, + deferred = {}; + + // Add list-specific methods + jQuery.each( tuples, function( i, tuple ) { + var list = tuple[ 2 ], + stateString = tuple[ 5 ]; + + // promise.progress = list.add + // promise.done = list.add + // promise.fail = list.add + promise[ tuple[ 1 ] ] = list.add; + + // Handle state + if ( stateString ) { + list.add( + function() { + + // state = "resolved" (i.e., fulfilled) + // state = "rejected" + state = stateString; + }, + + // rejected_callbacks.disable + // fulfilled_callbacks.disable + tuples[ 3 - i ][ 2 ].disable, + + // rejected_handlers.disable + // fulfilled_handlers.disable + tuples[ 3 - i ][ 3 ].disable, + + // progress_callbacks.lock + tuples[ 0 ][ 2 ].lock, + + // progress_handlers.lock + tuples[ 0 ][ 3 ].lock + ); + } + + // progress_handlers.fire + // fulfilled_handlers.fire + // rejected_handlers.fire + list.add( tuple[ 3 ].fire ); + + // deferred.notify = function() { deferred.notifyWith(...) } + // deferred.resolve = function() { deferred.resolveWith(...) } + // deferred.reject = function() { deferred.rejectWith(...) } + deferred[ tuple[ 0 ] ] = function() { + deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments ); + return this; + }; + + // deferred.notifyWith = list.fireWith + // deferred.resolveWith = list.fireWith + // deferred.rejectWith = list.fireWith + deferred[ tuple[ 0 ] + "With" ] = list.fireWith; + } ); + + // Make the deferred a promise + promise.promise( deferred ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( singleValue ) { + var + + // count of uncompleted subordinates + remaining = arguments.length, + + // count of unprocessed arguments + i = remaining, + + // subordinate fulfillment data + resolveContexts = Array( i ), + resolveValues = slice.call( arguments ), + + // the primary Deferred + primary = jQuery.Deferred(), + + // subordinate callback factory + updateFunc = function( i ) { + return function( value ) { + resolveContexts[ i ] = this; + resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; + if ( !( --remaining ) ) { + primary.resolveWith( resolveContexts, resolveValues ); + } + }; + }; + + // Single- and empty arguments are adopted like Promise.resolve + if ( remaining <= 1 ) { + adoptValue( singleValue, primary.done( updateFunc( i ) ).resolve, primary.reject, + !remaining ); + + // Use .then() to unwrap secondary thenables (cf. gh-3000) + if ( primary.state() === "pending" || + isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { + + return primary.then(); + } + } + + // Multiple arguments are aggregated like Promise.all array elements + while ( i-- ) { + adoptValue( resolveValues[ i ], updateFunc( i ), primary.reject ); + } + + return primary.promise(); + } +} ); + + +// These usually indicate a programmer mistake during development, +// warn about them ASAP rather than swallowing them by default. +var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/; + +jQuery.Deferred.exceptionHook = function( error, stack ) { + + // Support: IE 8 - 9 only + // Console exists when dev tools are open, which can happen at any time + if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) { + window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack ); + } +}; + + + + +jQuery.readyException = function( error ) { + window.setTimeout( function() { + throw error; + } ); +}; + + + + +// The deferred used on DOM ready +var readyList = jQuery.Deferred(); + +jQuery.fn.ready = function( fn ) { + + readyList + .then( fn ) + + // Wrap jQuery.readyException in a function so that the lookup + // happens at the time of error handling instead of callback + // registration. + .catch( function( error ) { + jQuery.readyException( error ); + } ); + + return this; +}; + +jQuery.extend( { + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Handle when the DOM is ready + ready: function( wait ) { + + // Abort if there are pending holds or we're already ready + if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { + return; + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith( document, [ jQuery ] ); + } +} ); + +jQuery.ready.then = readyList.then; + +// The ready event handler and self cleanup method +function completed() { + document.removeEventListener( "DOMContentLoaded", completed ); + window.removeEventListener( "load", completed ); + jQuery.ready(); +} + +// Catch cases where $(document).ready() is called +// after the browser event has already occurred. +// Support: IE <=9 - 10 only +// Older IE sometimes signals "interactive" too soon +if ( document.readyState === "complete" || + ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { + + // Handle it asynchronously to allow scripts the opportunity to delay ready + window.setTimeout( jQuery.ready ); + +} else { + + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", completed ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", completed ); +} + + + + +// Multifunctional method to get and set values of a collection +// The value/s can optionally be executed if it's a function +var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { + var i = 0, + len = elems.length, + bulk = key == null; + + // Sets many values + if ( toType( key ) === "object" ) { + chainable = true; + for ( i in key ) { + access( elems, fn, i, key[ i ], true, emptyGet, raw ); + } + + // Sets one value + } else if ( value !== undefined ) { + chainable = true; + + if ( !isFunction( value ) ) { + raw = true; + } + + if ( bulk ) { + + // Bulk operations run against the entire set + if ( raw ) { + fn.call( elems, value ); + fn = null; + + // ...except when executing function values + } else { + bulk = fn; + fn = function( elem, _key, value ) { + return bulk.call( jQuery( elem ), value ); + }; + } + } + + if ( fn ) { + for ( ; i < len; i++ ) { + fn( + elems[ i ], key, raw ? + value : + value.call( elems[ i ], i, fn( elems[ i ], key ) ) + ); + } + } + } + + if ( chainable ) { + return elems; + } + + // Gets + if ( bulk ) { + return fn.call( elems ); + } + + return len ? fn( elems[ 0 ], key ) : emptyGet; +}; + + +// Matches dashed string for camelizing +var rmsPrefix = /^-ms-/, + rdashAlpha = /-([a-z])/g; + +// Used by camelCase as callback to replace() +function fcamelCase( _all, letter ) { + return letter.toUpperCase(); +} + +// Convert dashed to camelCase; used by the css and data modules +// Support: IE <=9 - 11, Edge 12 - 15 +// Microsoft forgot to hump their vendor prefix (#9572) +function camelCase( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); +} +var acceptData = function( owner ) { + + // Accepts only: + // - Node + // - Node.ELEMENT_NODE + // - Node.DOCUMENT_NODE + // - Object + // - Any + return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); +}; + + + + +function Data() { + this.expando = jQuery.expando + Data.uid++; +} + +Data.uid = 1; + +Data.prototype = { + + cache: function( owner ) { + + // Check if the owner object already has a cache + var value = owner[ this.expando ]; + + // If not, create one + if ( !value ) { + value = {}; + + // We can accept data for non-element nodes in modern browsers, + // but we should not, see #8335. + // Always return an empty object. + if ( acceptData( owner ) ) { + + // If it is a node unlikely to be stringify-ed or looped over + // use plain assignment + if ( owner.nodeType ) { + owner[ this.expando ] = value; + + // Otherwise secure it in a non-enumerable property + // configurable must be true to allow the property to be + // deleted when data is removed + } else { + Object.defineProperty( owner, this.expando, { + value: value, + configurable: true + } ); + } + } + } + + return value; + }, + set: function( owner, data, value ) { + var prop, + cache = this.cache( owner ); + + // Handle: [ owner, key, value ] args + // Always use camelCase key (gh-2257) + if ( typeof data === "string" ) { + cache[ camelCase( data ) ] = value; + + // Handle: [ owner, { properties } ] args + } else { + + // Copy the properties one-by-one to the cache object + for ( prop in data ) { + cache[ camelCase( prop ) ] = data[ prop ]; + } + } + return cache; + }, + get: function( owner, key ) { + return key === undefined ? + this.cache( owner ) : + + // Always use camelCase key (gh-2257) + owner[ this.expando ] && owner[ this.expando ][ camelCase( key ) ]; + }, + access: function( owner, key, value ) { + + // In cases where either: + // + // 1. No key was specified + // 2. A string key was specified, but no value provided + // + // Take the "read" path and allow the get method to determine + // which value to return, respectively either: + // + // 1. The entire cache object + // 2. The data stored at the key + // + if ( key === undefined || + ( ( key && typeof key === "string" ) && value === undefined ) ) { + + return this.get( owner, key ); + } + + // When the key is not a string, or both a key and value + // are specified, set or extend (existing objects) with either: + // + // 1. An object of properties + // 2. A key and value + // + this.set( owner, key, value ); + + // Since the "set" path can have two possible entry points + // return the expected data based on which path was taken[*] + return value !== undefined ? value : key; + }, + remove: function( owner, key ) { + var i, + cache = owner[ this.expando ]; + + if ( cache === undefined ) { + return; + } + + if ( key !== undefined ) { + + // Support array or space separated string of keys + if ( Array.isArray( key ) ) { + + // If key is an array of keys... + // We always set camelCase keys, so remove that. + key = key.map( camelCase ); + } else { + key = camelCase( key ); + + // If a key with the spaces exists, use it. + // Otherwise, create an array by matching non-whitespace + key = key in cache ? + [ key ] : + ( key.match( rnothtmlwhite ) || [] ); + } + + i = key.length; + + while ( i-- ) { + delete cache[ key[ i ] ]; + } + } + + // Remove the expando if there's no more data + if ( key === undefined || jQuery.isEmptyObject( cache ) ) { + + // Support: Chrome <=35 - 45 + // Webkit & Blink performance suffers when deleting properties + // from DOM nodes, so set to undefined instead + // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted) + if ( owner.nodeType ) { + owner[ this.expando ] = undefined; + } else { + delete owner[ this.expando ]; + } + } + }, + hasData: function( owner ) { + var cache = owner[ this.expando ]; + return cache !== undefined && !jQuery.isEmptyObject( cache ); + } +}; +var dataPriv = new Data(); + +var dataUser = new Data(); + + + +// Implementation Summary +// +// 1. Enforce API surface and semantic compatibility with 1.9.x branch +// 2. Improve the module's maintainability by reducing the storage +// paths to a single mechanism. +// 3. Use the same single mechanism to support "private" and "user" data. +// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) +// 5. Avoid exposing implementation details on user objects (eg. expando properties) +// 6. Provide a clear path for implementation upgrade to WeakMap in 2014 + +var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, + rmultiDash = /[A-Z]/g; + +function getData( data ) { + if ( data === "true" ) { + return true; + } + + if ( data === "false" ) { + return false; + } + + if ( data === "null" ) { + return null; + } + + // Only convert to a number if it doesn't change the string + if ( data === +data + "" ) { + return +data; + } + + if ( rbrace.test( data ) ) { + return JSON.parse( data ); + } + + return data; +} + +function dataAttr( elem, key, data ) { + var name; + + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase(); + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = getData( data ); + } catch ( e ) {} + + // Make sure we set the data so it isn't changed later + dataUser.set( elem, key, data ); + } else { + data = undefined; + } + } + return data; +} + +jQuery.extend( { + hasData: function( elem ) { + return dataUser.hasData( elem ) || dataPriv.hasData( elem ); + }, + + data: function( elem, name, data ) { + return dataUser.access( elem, name, data ); + }, + + removeData: function( elem, name ) { + dataUser.remove( elem, name ); + }, + + // TODO: Now that all calls to _data and _removeData have been replaced + // with direct calls to dataPriv methods, these can be deprecated. + _data: function( elem, name, data ) { + return dataPriv.access( elem, name, data ); + }, + + _removeData: function( elem, name ) { + dataPriv.remove( elem, name ); + } +} ); + +jQuery.fn.extend( { + data: function( key, value ) { + var i, name, data, + elem = this[ 0 ], + attrs = elem && elem.attributes; + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = dataUser.get( elem ); + + if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) { + i = attrs.length; + while ( i-- ) { + + // Support: IE 11 only + // The attrs elements can be null (#14894) + if ( attrs[ i ] ) { + name = attrs[ i ].name; + if ( name.indexOf( "data-" ) === 0 ) { + name = camelCase( name.slice( 5 ) ); + dataAttr( elem, name, data[ name ] ); + } + } + } + dataPriv.set( elem, "hasDataAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each( function() { + dataUser.set( this, key ); + } ); + } + + return access( this, function( value ) { + var data; + + // The calling jQuery object (element matches) is not empty + // (and therefore has an element appears at this[ 0 ]) and the + // `value` parameter was not undefined. An empty jQuery object + // will result in `undefined` for elem = this[ 0 ] which will + // throw an exception if an attempt to read a data cache is made. + if ( elem && value === undefined ) { + + // Attempt to get data from the cache + // The key will always be camelCased in Data + data = dataUser.get( elem, key ); + if ( data !== undefined ) { + return data; + } + + // Attempt to "discover" the data in + // HTML5 custom data-* attrs + data = dataAttr( elem, key ); + if ( data !== undefined ) { + return data; + } + + // We tried really hard, but the data doesn't exist. + return; + } + + // Set the data... + this.each( function() { + + // We always store the camelCased key + dataUser.set( this, key, value ); + } ); + }, null, value, arguments.length > 1, null, true ); + }, + + removeData: function( key ) { + return this.each( function() { + dataUser.remove( this, key ); + } ); + } +} ); + + +jQuery.extend( { + queue: function( elem, type, data ) { + var queue; + + if ( elem ) { + type = ( type || "fx" ) + "queue"; + queue = dataPriv.get( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !queue || Array.isArray( data ) ) { + queue = dataPriv.access( elem, type, jQuery.makeArray( data ) ); + } else { + queue.push( data ); + } + } + return queue || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + startLength = queue.length, + fn = queue.shift(), + hooks = jQuery._queueHooks( elem, type ), + next = function() { + jQuery.dequeue( elem, type ); + }; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + startLength--; + } + + if ( fn ) { + + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + // Clear up the last queue stop function + delete hooks.stop; + fn.call( elem, next, hooks ); + } + + if ( !startLength && hooks ) { + hooks.empty.fire(); + } + }, + + // Not public - generate a queueHooks object, or return the current one + _queueHooks: function( elem, type ) { + var key = type + "queueHooks"; + return dataPriv.get( elem, key ) || dataPriv.access( elem, key, { + empty: jQuery.Callbacks( "once memory" ).add( function() { + dataPriv.remove( elem, [ type + "queue", key ] ); + } ) + } ); + } +} ); + +jQuery.fn.extend( { + queue: function( type, data ) { + var setter = 2; + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + setter--; + } + + if ( arguments.length < setter ) { + return jQuery.queue( this[ 0 ], type ); + } + + return data === undefined ? + this : + this.each( function() { + var queue = jQuery.queue( this, type, data ); + + // Ensure a hooks for this queue + jQuery._queueHooks( this, type ); + + if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + } ); + }, + dequeue: function( type ) { + return this.each( function() { + jQuery.dequeue( this, type ); + } ); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, obj ) { + var tmp, + count = 1, + defer = jQuery.Deferred(), + elements = this, + i = this.length, + resolve = function() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + }; + + if ( typeof type !== "string" ) { + obj = type; + type = undefined; + } + type = type || "fx"; + + while ( i-- ) { + tmp = dataPriv.get( elements[ i ], type + "queueHooks" ); + if ( tmp && tmp.empty ) { + count++; + tmp.empty.add( resolve ); + } + } + resolve(); + return defer.promise( obj ); + } +} ); +var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; + +var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); + + +var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; + +var documentElement = document.documentElement; + + + + var isAttached = function( elem ) { + return jQuery.contains( elem.ownerDocument, elem ); + }, + composed = { composed: true }; + + // Support: IE 9 - 11+, Edge 12 - 18+, iOS 10.0 - 10.2 only + // Check attachment across shadow DOM boundaries when possible (gh-3504) + // Support: iOS 10.0-10.2 only + // Early iOS 10 versions support `attachShadow` but not `getRootNode`, + // leading to errors. We need to check for `getRootNode`. + if ( documentElement.getRootNode ) { + isAttached = function( elem ) { + return jQuery.contains( elem.ownerDocument, elem ) || + elem.getRootNode( composed ) === elem.ownerDocument; + }; + } +var isHiddenWithinTree = function( elem, el ) { + + // isHiddenWithinTree might be called from jQuery#filter function; + // in that case, element will be second argument + elem = el || elem; + + // Inline style trumps all + return elem.style.display === "none" || + elem.style.display === "" && + + // Otherwise, check computed style + // Support: Firefox <=43 - 45 + // Disconnected elements can have computed display: none, so first confirm that elem is + // in the document. + isAttached( elem ) && + + jQuery.css( elem, "display" ) === "none"; + }; + + + +function adjustCSS( elem, prop, valueParts, tween ) { + var adjusted, scale, + maxIterations = 20, + currentValue = tween ? + function() { + return tween.cur(); + } : + function() { + return jQuery.css( elem, prop, "" ); + }, + initial = currentValue(), + unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), + + // Starting value computation is required for potential unit mismatches + initialInUnit = elem.nodeType && + ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && + rcssNum.exec( jQuery.css( elem, prop ) ); + + if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { + + // Support: Firefox <=54 + // Halve the iteration target value to prevent interference from CSS upper bounds (gh-2144) + initial = initial / 2; + + // Trust units reported by jQuery.css + unit = unit || initialInUnit[ 3 ]; + + // Iteratively approximate from a nonzero starting point + initialInUnit = +initial || 1; + + while ( maxIterations-- ) { + + // Evaluate and update our best guess (doubling guesses that zero out). + // Finish if the scale equals or crosses 1 (making the old*new product non-positive). + jQuery.style( elem, prop, initialInUnit + unit ); + if ( ( 1 - scale ) * ( 1 - ( scale = currentValue() / initial || 0.5 ) ) <= 0 ) { + maxIterations = 0; + } + initialInUnit = initialInUnit / scale; + + } + + initialInUnit = initialInUnit * 2; + jQuery.style( elem, prop, initialInUnit + unit ); + + // Make sure we update the tween properties later on + valueParts = valueParts || []; + } + + if ( valueParts ) { + initialInUnit = +initialInUnit || +initial || 0; + + // Apply relative offset (+=/-=) if specified + adjusted = valueParts[ 1 ] ? + initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] : + +valueParts[ 2 ]; + if ( tween ) { + tween.unit = unit; + tween.start = initialInUnit; + tween.end = adjusted; + } + } + return adjusted; +} + + +var defaultDisplayMap = {}; + +function getDefaultDisplay( elem ) { + var temp, + doc = elem.ownerDocument, + nodeName = elem.nodeName, + display = defaultDisplayMap[ nodeName ]; + + if ( display ) { + return display; + } + + temp = doc.body.appendChild( doc.createElement( nodeName ) ); + display = jQuery.css( temp, "display" ); + + temp.parentNode.removeChild( temp ); + + if ( display === "none" ) { + display = "block"; + } + defaultDisplayMap[ nodeName ] = display; + + return display; +} + +function showHide( elements, show ) { + var display, elem, + values = [], + index = 0, + length = elements.length; + + // Determine new display value for elements that need to change + for ( ; index < length; index++ ) { + elem = elements[ index ]; + if ( !elem.style ) { + continue; + } + + display = elem.style.display; + if ( show ) { + + // Since we force visibility upon cascade-hidden elements, an immediate (and slow) + // check is required in this first loop unless we have a nonempty display value (either + // inline or about-to-be-restored) + if ( display === "none" ) { + values[ index ] = dataPriv.get( elem, "display" ) || null; + if ( !values[ index ] ) { + elem.style.display = ""; + } + } + if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) { + values[ index ] = getDefaultDisplay( elem ); + } + } else { + if ( display !== "none" ) { + values[ index ] = "none"; + + // Remember what we're overwriting + dataPriv.set( elem, "display", display ); + } + } + } + + // Set the display of the elements in a second loop to avoid constant reflow + for ( index = 0; index < length; index++ ) { + if ( values[ index ] != null ) { + elements[ index ].style.display = values[ index ]; + } + } + + return elements; +} + +jQuery.fn.extend( { + show: function() { + return showHide( this, true ); + }, + hide: function() { + return showHide( this ); + }, + toggle: function( state ) { + if ( typeof state === "boolean" ) { + return state ? this.show() : this.hide(); + } + + return this.each( function() { + if ( isHiddenWithinTree( this ) ) { + jQuery( this ).show(); + } else { + jQuery( this ).hide(); + } + } ); + } +} ); +var rcheckableType = ( /^(?:checkbox|radio)$/i ); + +var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]*)/i ); + +var rscriptType = ( /^$|^module$|\/(?:java|ecma)script/i ); + + + +( function() { + var fragment = document.createDocumentFragment(), + div = fragment.appendChild( document.createElement( "div" ) ), + input = document.createElement( "input" ); + + // Support: Android 4.0 - 4.3 only + // Check state lost if the name is set (#11217) + // Support: Windows Web Apps (WWA) + // `name` and `type` must use .setAttribute for WWA (#14901) + input.setAttribute( "type", "radio" ); + input.setAttribute( "checked", "checked" ); + input.setAttribute( "name", "t" ); + + div.appendChild( input ); + + // Support: Android <=4.1 only + // Older WebKit doesn't clone checked state correctly in fragments + support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Support: IE <=11 only + // Make sure textarea (and checkbox) defaultValue is properly cloned + div.innerHTML = ""; + support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; + + // Support: IE <=9 only + // IE <=9 replaces "; + support.option = !!div.lastChild; +} )(); + + +// We have to close these tags to support XHTML (#13200) +var wrapMap = { + + // XHTML parsers do not magically insert elements in the + // same way that tag soup parsers do. So we cannot shorten + // this by omitting or other required elements. + thead: [ 1, "", "
" ], + col: [ 2, "", "
" ], + tr: [ 2, "", "
" ], + td: [ 3, "", "
" ], + + _default: [ 0, "", "" ] +}; + +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + +// Support: IE <=9 only +if ( !support.option ) { + wrapMap.optgroup = wrapMap.option = [ 1, "" ]; +} + + +function getAll( context, tag ) { + + // Support: IE <=9 - 11 only + // Use typeof to avoid zero-argument method invocation on host objects (#15151) + var ret; + + if ( typeof context.getElementsByTagName !== "undefined" ) { + ret = context.getElementsByTagName( tag || "*" ); + + } else if ( typeof context.querySelectorAll !== "undefined" ) { + ret = context.querySelectorAll( tag || "*" ); + + } else { + ret = []; + } + + if ( tag === undefined || tag && nodeName( context, tag ) ) { + return jQuery.merge( [ context ], ret ); + } + + return ret; +} + + +// Mark scripts as having already been evaluated +function setGlobalEval( elems, refElements ) { + var i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + dataPriv.set( + elems[ i ], + "globalEval", + !refElements || dataPriv.get( refElements[ i ], "globalEval" ) + ); + } +} + + +var rhtml = /<|&#?\w+;/; + +function buildFragment( elems, context, scripts, selection, ignored ) { + var elem, tmp, tag, wrap, attached, j, + fragment = context.createDocumentFragment(), + nodes = [], + i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + elem = elems[ i ]; + + if ( elem || elem === 0 ) { + + // Add nodes directly + if ( toType( elem ) === "object" ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); + + // Convert non-html into a text node + } else if ( !rhtml.test( elem ) ) { + nodes.push( context.createTextNode( elem ) ); + + // Convert html into DOM nodes + } else { + tmp = tmp || fragment.appendChild( context.createElement( "div" ) ); + + // Deserialize a standard representation + tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase(); + wrap = wrapMap[ tag ] || wrapMap._default; + tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ]; + + // Descend through wrappers to the right content + j = wrap[ 0 ]; + while ( j-- ) { + tmp = tmp.lastChild; + } + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, tmp.childNodes ); + + // Remember the top-level container + tmp = fragment.firstChild; + + // Ensure the created nodes are orphaned (#12392) + tmp.textContent = ""; + } + } + } + + // Remove wrapper from fragment + fragment.textContent = ""; + + i = 0; + while ( ( elem = nodes[ i++ ] ) ) { + + // Skip elements already in the context collection (trac-4087) + if ( selection && jQuery.inArray( elem, selection ) > -1 ) { + if ( ignored ) { + ignored.push( elem ); + } + continue; + } + + attached = isAttached( elem ); + + // Append to fragment + tmp = getAll( fragment.appendChild( elem ), "script" ); + + // Preserve script evaluation history + if ( attached ) { + setGlobalEval( tmp ); + } + + // Capture executables + if ( scripts ) { + j = 0; + while ( ( elem = tmp[ j++ ] ) ) { + if ( rscriptType.test( elem.type || "" ) ) { + scripts.push( elem ); + } + } + } + } + + return fragment; +} + + +var rtypenamespace = /^([^.]*)(?:\.(.+)|)/; + +function returnTrue() { + return true; +} + +function returnFalse() { + return false; +} + +// Support: IE <=9 - 11+ +// focus() and blur() are asynchronous, except when they are no-op. +// So expect focus to be synchronous when the element is already active, +// and blur to be synchronous when the element is not already active. +// (focus and blur are always synchronous in other supported browsers, +// this just defines when we can count on it). +function expectSync( elem, type ) { + return ( elem === safeActiveElement() ) === ( type === "focus" ); +} + +// Support: IE <=9 only +// Accessing document.activeElement can throw unexpectedly +// https://bugs.jquery.com/ticket/13393 +function safeActiveElement() { + try { + return document.activeElement; + } catch ( err ) { } +} + +function on( elem, types, selector, data, fn, one ) { + var origFn, type; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { + + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + on( elem, type, selector, data, types[ type ], one ); + } + return elem; + } + + if ( data == null && fn == null ) { + + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return elem; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return elem.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + } ); +} + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + global: {}, + + add: function( elem, types, handler, data, selector ) { + + var handleObjIn, eventHandle, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.get( elem ); + + // Only attach events to objects that accept data + if ( !acceptData( elem ) ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Ensure that invalid selectors throw exceptions at attach time + // Evaluate against documentElement in case elem is a non-element node (e.g., document) + if ( selector ) { + jQuery.find.matchesSelector( documentElement, selector ); + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + if ( !( events = elemData.events ) ) { + events = elemData.events = Object.create( null ); + } + if ( !( eventHandle = elemData.handle ) ) { + eventHandle = elemData.handle = function( e ) { + + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? + jQuery.event.dispatch.apply( elem, arguments ) : undefined; + }; + } + + // Handle multiple events separated by a space + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // There *must* be a type, no attaching namespace-only handlers + if ( !type ) { + continue; + } + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend( { + type: type, + origType: origType, + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + needsContext: selector && jQuery.expr.match.needsContext.test( selector ), + namespace: namespaces.join( "." ) + }, handleObjIn ); + + // Init the event handler queue if we're the first + if ( !( handlers = events[ type ] ) ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener if the special events handler returns false + if ( !special.setup || + special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + }, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + + var j, origCount, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.hasData( elem ) && dataPriv.get( elem ); + + if ( !elemData || !( events = elemData.events ) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector ? special.delegateType : special.bindType ) || type; + handlers = events[ type ] || []; + tmp = tmp[ 2 ] && + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ); + + // Remove matching events + origCount = j = handlers.length; + while ( j-- ) { + handleObj = handlers[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !tmp || tmp.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || + selector === "**" && handleObj.selector ) ) { + handlers.splice( j, 1 ); + + if ( handleObj.selector ) { + handlers.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( origCount && !handlers.length ) { + if ( !special.teardown || + special.teardown.call( elem, namespaces, elemData.handle ) === false ) { + + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove data and the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + dataPriv.remove( elem, "handle events" ); + } + }, + + dispatch: function( nativeEvent ) { + + var i, j, ret, matched, handleObj, handlerQueue, + args = new Array( arguments.length ), + + // Make a writable jQuery.Event from the native event object + event = jQuery.event.fix( nativeEvent ), + + handlers = ( + dataPriv.get( this, "events" ) || Object.create( null ) + )[ event.type ] || [], + special = jQuery.event.special[ event.type ] || {}; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[ 0 ] = event; + + for ( i = 1; i < arguments.length; i++ ) { + args[ i ] = arguments[ i ]; + } + + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers + handlerQueue = jQuery.event.handlers.call( this, event, handlers ); + + // Run delegates first; they may want to stop propagation beneath us + i = 0; + while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { + event.currentTarget = matched.elem; + + j = 0; + while ( ( handleObj = matched.handlers[ j++ ] ) && + !event.isImmediatePropagationStopped() ) { + + // If the event is namespaced, then each handler is only invoked if it is + // specially universal or its namespaces are a superset of the event's. + if ( !event.rnamespace || handleObj.namespace === false || + event.rnamespace.test( handleObj.namespace ) ) { + + event.handleObj = handleObj; + event.data = handleObj.data; + + ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle || + handleObj.handler ).apply( matched.elem, args ); + + if ( ret !== undefined ) { + if ( ( event.result = ret ) === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + handlers: function( event, handlers ) { + var i, handleObj, sel, matchedHandlers, matchedSelectors, + handlerQueue = [], + delegateCount = handlers.delegateCount, + cur = event.target; + + // Find delegate handlers + if ( delegateCount && + + // Support: IE <=9 + // Black-hole SVG instance trees (trac-13180) + cur.nodeType && + + // Support: Firefox <=42 + // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861) + // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click + // Support: IE 11 only + // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343) + !( event.type === "click" && event.button >= 1 ) ) { + + for ( ; cur !== this; cur = cur.parentNode || this ) { + + // Don't check non-elements (#13208) + // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) + if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) { + matchedHandlers = []; + matchedSelectors = {}; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + + // Don't conflict with Object.prototype properties (#13203) + sel = handleObj.selector + " "; + + if ( matchedSelectors[ sel ] === undefined ) { + matchedSelectors[ sel ] = handleObj.needsContext ? + jQuery( sel, this ).index( cur ) > -1 : + jQuery.find( sel, this, null, [ cur ] ).length; + } + if ( matchedSelectors[ sel ] ) { + matchedHandlers.push( handleObj ); + } + } + if ( matchedHandlers.length ) { + handlerQueue.push( { elem: cur, handlers: matchedHandlers } ); + } + } + } + } + + // Add the remaining (directly-bound) handlers + cur = this; + if ( delegateCount < handlers.length ) { + handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } ); + } + + return handlerQueue; + }, + + addProp: function( name, hook ) { + Object.defineProperty( jQuery.Event.prototype, name, { + enumerable: true, + configurable: true, + + get: isFunction( hook ) ? + function() { + if ( this.originalEvent ) { + return hook( this.originalEvent ); + } + } : + function() { + if ( this.originalEvent ) { + return this.originalEvent[ name ]; + } + }, + + set: function( value ) { + Object.defineProperty( this, name, { + enumerable: true, + configurable: true, + writable: true, + value: value + } ); + } + } ); + }, + + fix: function( originalEvent ) { + return originalEvent[ jQuery.expando ] ? + originalEvent : + new jQuery.Event( originalEvent ); + }, + + special: { + load: { + + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + click: { + + // Utilize native event to ensure correct state for checkable inputs + setup: function( data ) { + + // For mutual compressibility with _default, replace `this` access with a local var. + // `|| data` is dead code meant only to preserve the variable through minification. + var el = this || data; + + // Claim the first handler + if ( rcheckableType.test( el.type ) && + el.click && nodeName( el, "input" ) ) { + + // dataPriv.set( el, "click", ... ) + leverageNative( el, "click", returnTrue ); + } + + // Return false to allow normal processing in the caller + return false; + }, + trigger: function( data ) { + + // For mutual compressibility with _default, replace `this` access with a local var. + // `|| data` is dead code meant only to preserve the variable through minification. + var el = this || data; + + // Force setup before triggering a click + if ( rcheckableType.test( el.type ) && + el.click && nodeName( el, "input" ) ) { + + leverageNative( el, "click" ); + } + + // Return non-false to allow normal event-path propagation + return true; + }, + + // For cross-browser consistency, suppress native .click() on links + // Also prevent it if we're currently inside a leveraged native-event stack + _default: function( event ) { + var target = event.target; + return rcheckableType.test( target.type ) && + target.click && nodeName( target, "input" ) && + dataPriv.get( target, "click" ) || + nodeName( target, "a" ); + } + }, + + beforeunload: { + postDispatch: function( event ) { + + // Support: Firefox 20+ + // Firefox doesn't alert if the returnValue field is not set. + if ( event.result !== undefined && event.originalEvent ) { + event.originalEvent.returnValue = event.result; + } + } + } + } +}; + +// Ensure the presence of an event listener that handles manually-triggered +// synthetic events by interrupting progress until reinvoked in response to +// *native* events that it fires directly, ensuring that state changes have +// already occurred before other listeners are invoked. +function leverageNative( el, type, expectSync ) { + + // Missing expectSync indicates a trigger call, which must force setup through jQuery.event.add + if ( !expectSync ) { + if ( dataPriv.get( el, type ) === undefined ) { + jQuery.event.add( el, type, returnTrue ); + } + return; + } + + // Register the controller as a special universal handler for all event namespaces + dataPriv.set( el, type, false ); + jQuery.event.add( el, type, { + namespace: false, + handler: function( event ) { + var notAsync, result, + saved = dataPriv.get( this, type ); + + if ( ( event.isTrigger & 1 ) && this[ type ] ) { + + // Interrupt processing of the outer synthetic .trigger()ed event + // Saved data should be false in such cases, but might be a leftover capture object + // from an async native handler (gh-4350) + if ( !saved.length ) { + + // Store arguments for use when handling the inner native event + // There will always be at least one argument (an event object), so this array + // will not be confused with a leftover capture object. + saved = slice.call( arguments ); + dataPriv.set( this, type, saved ); + + // Trigger the native event and capture its result + // Support: IE <=9 - 11+ + // focus() and blur() are asynchronous + notAsync = expectSync( this, type ); + this[ type ](); + result = dataPriv.get( this, type ); + if ( saved !== result || notAsync ) { + dataPriv.set( this, type, false ); + } else { + result = {}; + } + if ( saved !== result ) { + + // Cancel the outer synthetic event + event.stopImmediatePropagation(); + event.preventDefault(); + + // Support: Chrome 86+ + // In Chrome, if an element having a focusout handler is blurred by + // clicking outside of it, it invokes the handler synchronously. If + // that handler calls `.remove()` on the element, the data is cleared, + // leaving `result` undefined. We need to guard against this. + return result && result.value; + } + + // If this is an inner synthetic event for an event with a bubbling surrogate + // (focus or blur), assume that the surrogate already propagated from triggering the + // native event and prevent that from happening again here. + // This technically gets the ordering wrong w.r.t. to `.trigger()` (in which the + // bubbling surrogate propagates *after* the non-bubbling base), but that seems + // less bad than duplication. + } else if ( ( jQuery.event.special[ type ] || {} ).delegateType ) { + event.stopPropagation(); + } + + // If this is a native event triggered above, everything is now in order + // Fire an inner synthetic event with the original arguments + } else if ( saved.length ) { + + // ...and capture the result + dataPriv.set( this, type, { + value: jQuery.event.trigger( + + // Support: IE <=9 - 11+ + // Extend with the prototype to reset the above stopImmediatePropagation() + jQuery.extend( saved[ 0 ], jQuery.Event.prototype ), + saved.slice( 1 ), + this + ) + } ); + + // Abort handling of the native event + event.stopImmediatePropagation(); + } + } + } ); +} + +jQuery.removeEvent = function( elem, type, handle ) { + + // This "if" is needed for plain objects + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle ); + } +}; + +jQuery.Event = function( src, props ) { + + // Allow instantiation without the 'new' keyword + if ( !( this instanceof jQuery.Event ) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = src.defaultPrevented || + src.defaultPrevented === undefined && + + // Support: Android <=2.3 only + src.returnValue === false ? + returnTrue : + returnFalse; + + // Create target properties + // Support: Safari <=6 - 7 only + // Target should not be a text node (#504, #13143) + this.target = ( src.target && src.target.nodeType === 3 ) ? + src.target.parentNode : + src.target; + + this.currentTarget = src.currentTarget; + this.relatedTarget = src.relatedTarget; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || Date.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + constructor: jQuery.Event, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse, + isSimulated: false, + + preventDefault: function() { + var e = this.originalEvent; + + this.isDefaultPrevented = returnTrue; + + if ( e && !this.isSimulated ) { + e.preventDefault(); + } + }, + stopPropagation: function() { + var e = this.originalEvent; + + this.isPropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopPropagation(); + } + }, + stopImmediatePropagation: function() { + var e = this.originalEvent; + + this.isImmediatePropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopImmediatePropagation(); + } + + this.stopPropagation(); + } +}; + +// Includes all common event props including KeyEvent and MouseEvent specific props +jQuery.each( { + altKey: true, + bubbles: true, + cancelable: true, + changedTouches: true, + ctrlKey: true, + detail: true, + eventPhase: true, + metaKey: true, + pageX: true, + pageY: true, + shiftKey: true, + view: true, + "char": true, + code: true, + charCode: true, + key: true, + keyCode: true, + button: true, + buttons: true, + clientX: true, + clientY: true, + offsetX: true, + offsetY: true, + pointerId: true, + pointerType: true, + screenX: true, + screenY: true, + targetTouches: true, + toElement: true, + touches: true, + which: true +}, jQuery.event.addProp ); + +jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateType ) { + jQuery.event.special[ type ] = { + + // Utilize native event if possible so blur/focus sequence is correct + setup: function() { + + // Claim the first handler + // dataPriv.set( this, "focus", ... ) + // dataPriv.set( this, "blur", ... ) + leverageNative( this, type, expectSync ); + + // Return false to allow normal processing in the caller + return false; + }, + trigger: function() { + + // Force setup before trigger + leverageNative( this, type ); + + // Return non-false to allow normal event-path propagation + return true; + }, + + // Suppress native focus or blur as it's already being fired + // in leverageNative. + _default: function() { + return true; + }, + + delegateType: delegateType + }; +} ); + +// Create mouseenter/leave events using mouseover/out and event-time checks +// so that event delegation works in jQuery. +// Do the same for pointerenter/pointerleave and pointerover/pointerout +// +// Support: Safari 7 only +// Safari sends mouseenter too often; see: +// https://bugs.chromium.org/p/chromium/issues/detail?id=470258 +// for the description of the bug (it existed in older Chrome versions as well). +jQuery.each( { + mouseenter: "mouseover", + mouseleave: "mouseout", + pointerenter: "pointerover", + pointerleave: "pointerout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var ret, + target = this, + related = event.relatedTarget, + handleObj = event.handleObj; + + // For mouseenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +} ); + +jQuery.fn.extend( { + + on: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn ); + }, + one: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + var handleObj, type; + if ( types && types.preventDefault && types.handleObj ) { + + // ( event ) dispatched jQuery.Event + handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? + handleObj.origType + "." + handleObj.namespace : + handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + + // ( types-object [, selector] ) + for ( type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each( function() { + jQuery.event.remove( this, types, fn, selector ); + } ); + } +} ); + + +var + + // Support: IE <=10 - 11, Edge 12 - 13 only + // In IE/Edge using regex groups here causes severe slowdowns. + // See https://connect.microsoft.com/IE/feedback/details/1736512/ + rnoInnerhtml = /\s*$/g; + +// Prefer a tbody over its parent table for containing new rows +function manipulationTarget( elem, content ) { + if ( nodeName( elem, "table" ) && + nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) { + + return jQuery( elem ).children( "tbody" )[ 0 ] || elem; + } + + return elem; +} + +// Replace/restore the type attribute of script elements for safe DOM manipulation +function disableScript( elem ) { + elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type; + return elem; +} +function restoreScript( elem ) { + if ( ( elem.type || "" ).slice( 0, 5 ) === "true/" ) { + elem.type = elem.type.slice( 5 ); + } else { + elem.removeAttribute( "type" ); + } + + return elem; +} + +function cloneCopyEvent( src, dest ) { + var i, l, type, pdataOld, udataOld, udataCur, events; + + if ( dest.nodeType !== 1 ) { + return; + } + + // 1. Copy private data: events, handlers, etc. + if ( dataPriv.hasData( src ) ) { + pdataOld = dataPriv.get( src ); + events = pdataOld.events; + + if ( events ) { + dataPriv.remove( dest, "handle events" ); + + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type, events[ type ][ i ] ); + } + } + } + } + + // 2. Copy user data + if ( dataUser.hasData( src ) ) { + udataOld = dataUser.access( src ); + udataCur = jQuery.extend( {}, udataOld ); + + dataUser.set( dest, udataCur ); + } +} + +// Fix IE bugs, see support tests +function fixInput( src, dest ) { + var nodeName = dest.nodeName.toLowerCase(); + + // Fails to persist the checked state of a cloned checkbox or radio button. + if ( nodeName === "input" && rcheckableType.test( src.type ) ) { + dest.checked = src.checked; + + // Fails to return the selected option to the default selected state when cloning options + } else if ( nodeName === "input" || nodeName === "textarea" ) { + dest.defaultValue = src.defaultValue; + } +} + +function domManip( collection, args, callback, ignored ) { + + // Flatten any nested arrays + args = flat( args ); + + var fragment, first, scripts, hasScripts, node, doc, + i = 0, + l = collection.length, + iNoClone = l - 1, + value = args[ 0 ], + valueIsFunction = isFunction( value ); + + // We can't cloneNode fragments that contain checked, in WebKit + if ( valueIsFunction || + ( l > 1 && typeof value === "string" && + !support.checkClone && rchecked.test( value ) ) ) { + return collection.each( function( index ) { + var self = collection.eq( index ); + if ( valueIsFunction ) { + args[ 0 ] = value.call( this, index, self.html() ); + } + domManip( self, args, callback, ignored ); + } ); + } + + if ( l ) { + fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); + first = fragment.firstChild; + + if ( fragment.childNodes.length === 1 ) { + fragment = first; + } + + // Require either new content or an interest in ignored elements to invoke the callback + if ( first || ignored ) { + scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); + hasScripts = scripts.length; + + // Use the original fragment for the last item + // instead of the first because it can end up + // being emptied incorrectly in certain situations (#8070). + for ( ; i < l; i++ ) { + node = fragment; + + if ( i !== iNoClone ) { + node = jQuery.clone( node, true, true ); + + // Keep references to cloned scripts for later restoration + if ( hasScripts ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( scripts, getAll( node, "script" ) ); + } + } + + callback.call( collection[ i ], node, i ); + } + + if ( hasScripts ) { + doc = scripts[ scripts.length - 1 ].ownerDocument; + + // Reenable scripts + jQuery.map( scripts, restoreScript ); + + // Evaluate executable scripts on first document insertion + for ( i = 0; i < hasScripts; i++ ) { + node = scripts[ i ]; + if ( rscriptType.test( node.type || "" ) && + !dataPriv.access( node, "globalEval" ) && + jQuery.contains( doc, node ) ) { + + if ( node.src && ( node.type || "" ).toLowerCase() !== "module" ) { + + // Optional AJAX dependency, but won't run scripts if not present + if ( jQuery._evalUrl && !node.noModule ) { + jQuery._evalUrl( node.src, { + nonce: node.nonce || node.getAttribute( "nonce" ) + }, doc ); + } + } else { + DOMEval( node.textContent.replace( rcleanScript, "" ), node, doc ); + } + } + } + } + } + } + + return collection; +} + +function remove( elem, selector, keepData ) { + var node, + nodes = selector ? jQuery.filter( selector, elem ) : elem, + i = 0; + + for ( ; ( node = nodes[ i ] ) != null; i++ ) { + if ( !keepData && node.nodeType === 1 ) { + jQuery.cleanData( getAll( node ) ); + } + + if ( node.parentNode ) { + if ( keepData && isAttached( node ) ) { + setGlobalEval( getAll( node, "script" ) ); + } + node.parentNode.removeChild( node ); + } + } + + return elem; +} + +jQuery.extend( { + htmlPrefilter: function( html ) { + return html; + }, + + clone: function( elem, dataAndEvents, deepDataAndEvents ) { + var i, l, srcElements, destElements, + clone = elem.cloneNode( true ), + inPage = isAttached( elem ); + + // Fix IE cloning issues + if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && + !jQuery.isXMLDoc( elem ) ) { + + // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2 + destElements = getAll( clone ); + srcElements = getAll( elem ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + fixInput( srcElements[ i ], destElements[ i ] ); + } + } + + // Copy the events from the original to the clone + if ( dataAndEvents ) { + if ( deepDataAndEvents ) { + srcElements = srcElements || getAll( elem ); + destElements = destElements || getAll( clone ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + cloneCopyEvent( srcElements[ i ], destElements[ i ] ); + } + } else { + cloneCopyEvent( elem, clone ); + } + } + + // Preserve script evaluation history + destElements = getAll( clone, "script" ); + if ( destElements.length > 0 ) { + setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); + } + + // Return the cloned set + return clone; + }, + + cleanData: function( elems ) { + var data, elem, type, + special = jQuery.event.special, + i = 0; + + for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) { + if ( acceptData( elem ) ) { + if ( ( data = elem[ dataPriv.expando ] ) ) { + if ( data.events ) { + for ( type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } + } + } + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataPriv.expando ] = undefined; + } + if ( elem[ dataUser.expando ] ) { + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataUser.expando ] = undefined; + } + } + } + } +} ); + +jQuery.fn.extend( { + detach: function( selector ) { + return remove( this, selector, true ); + }, + + remove: function( selector ) { + return remove( this, selector ); + }, + + text: function( value ) { + return access( this, function( value ) { + return value === undefined ? + jQuery.text( this ) : + this.empty().each( function() { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + this.textContent = value; + } + } ); + }, null, value, arguments.length ); + }, + + append: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.appendChild( elem ); + } + } ); + }, + + prepend: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.insertBefore( elem, target.firstChild ); + } + } ); + }, + + before: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this ); + } + } ); + }, + + after: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + } + } ); + }, + + empty: function() { + var elem, + i = 0; + + for ( ; ( elem = this[ i ] ) != null; i++ ) { + if ( elem.nodeType === 1 ) { + + // Prevent memory leaks + jQuery.cleanData( getAll( elem, false ) ); + + // Remove any remaining nodes + elem.textContent = ""; + } + } + + return this; + }, + + clone: function( dataAndEvents, deepDataAndEvents ) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + + return this.map( function() { + return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); + } ); + }, + + html: function( value ) { + return access( this, function( value ) { + var elem = this[ 0 ] || {}, + i = 0, + l = this.length; + + if ( value === undefined && elem.nodeType === 1 ) { + return elem.innerHTML; + } + + // See if we can take a shortcut and just use innerHTML + if ( typeof value === "string" && !rnoInnerhtml.test( value ) && + !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { + + value = jQuery.htmlPrefilter( value ); + + try { + for ( ; i < l; i++ ) { + elem = this[ i ] || {}; + + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + elem.innerHTML = value; + } + } + + elem = 0; + + // If using innerHTML throws an exception, use the fallback method + } catch ( e ) {} + } + + if ( elem ) { + this.empty().append( value ); + } + }, null, value, arguments.length ); + }, + + replaceWith: function() { + var ignored = []; + + // Make the changes, replacing each non-ignored context element with the new content + return domManip( this, arguments, function( elem ) { + var parent = this.parentNode; + + if ( jQuery.inArray( this, ignored ) < 0 ) { + jQuery.cleanData( getAll( this ) ); + if ( parent ) { + parent.replaceChild( elem, this ); + } + } + + // Force callback invocation + }, ignored ); + } +} ); + +jQuery.each( { + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var elems, + ret = [], + insert = jQuery( selector ), + last = insert.length - 1, + i = 0; + + for ( ; i <= last; i++ ) { + elems = i === last ? this : this.clone( true ); + jQuery( insert[ i ] )[ original ]( elems ); + + // Support: Android <=4.0 only, PhantomJS 1 only + // .get() because push.apply(_, arraylike) throws on ancient WebKit + push.apply( ret, elems.get() ); + } + + return this.pushStack( ret ); + }; +} ); +var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); + +var getStyles = function( elem ) { + + // Support: IE <=11 only, Firefox <=30 (#15098, #14150) + // IE throws on elements created in popups + // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" + var view = elem.ownerDocument.defaultView; + + if ( !view || !view.opener ) { + view = window; + } + + return view.getComputedStyle( elem ); + }; + +var swap = function( elem, options, callback ) { + var ret, name, + old = {}; + + // Remember the old values, and insert the new ones + for ( name in options ) { + old[ name ] = elem.style[ name ]; + elem.style[ name ] = options[ name ]; + } + + ret = callback.call( elem ); + + // Revert the old values + for ( name in options ) { + elem.style[ name ] = old[ name ]; + } + + return ret; +}; + + +var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" ); + + + +( function() { + + // Executing both pixelPosition & boxSizingReliable tests require only one layout + // so they're executed at the same time to save the second computation. + function computeStyleTests() { + + // This is a singleton, we need to execute it only once + if ( !div ) { + return; + } + + container.style.cssText = "position:absolute;left:-11111px;width:60px;" + + "margin-top:1px;padding:0;border:0"; + div.style.cssText = + "position:relative;display:block;box-sizing:border-box;overflow:scroll;" + + "margin:auto;border:1px;padding:1px;" + + "width:60%;top:1%"; + documentElement.appendChild( container ).appendChild( div ); + + var divStyle = window.getComputedStyle( div ); + pixelPositionVal = divStyle.top !== "1%"; + + // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44 + reliableMarginLeftVal = roundPixelMeasures( divStyle.marginLeft ) === 12; + + // Support: Android 4.0 - 4.3 only, Safari <=9.1 - 10.1, iOS <=7.0 - 9.3 + // Some styles come back with percentage values, even though they shouldn't + div.style.right = "60%"; + pixelBoxStylesVal = roundPixelMeasures( divStyle.right ) === 36; + + // Support: IE 9 - 11 only + // Detect misreporting of content dimensions for box-sizing:border-box elements + boxSizingReliableVal = roundPixelMeasures( divStyle.width ) === 36; + + // Support: IE 9 only + // Detect overflow:scroll screwiness (gh-3699) + // Support: Chrome <=64 + // Don't get tricked when zoom affects offsetWidth (gh-4029) + div.style.position = "absolute"; + scrollboxSizeVal = roundPixelMeasures( div.offsetWidth / 3 ) === 12; + + documentElement.removeChild( container ); + + // Nullify the div so it wouldn't be stored in the memory and + // it will also be a sign that checks already performed + div = null; + } + + function roundPixelMeasures( measure ) { + return Math.round( parseFloat( measure ) ); + } + + var pixelPositionVal, boxSizingReliableVal, scrollboxSizeVal, pixelBoxStylesVal, + reliableTrDimensionsVal, reliableMarginLeftVal, + container = document.createElement( "div" ), + div = document.createElement( "div" ); + + // Finish early in limited (non-browser) environments + if ( !div.style ) { + return; + } + + // Support: IE <=9 - 11 only + // Style of cloned element affects source element cloned (#8908) + div.style.backgroundClip = "content-box"; + div.cloneNode( true ).style.backgroundClip = ""; + support.clearCloneStyle = div.style.backgroundClip === "content-box"; + + jQuery.extend( support, { + boxSizingReliable: function() { + computeStyleTests(); + return boxSizingReliableVal; + }, + pixelBoxStyles: function() { + computeStyleTests(); + return pixelBoxStylesVal; + }, + pixelPosition: function() { + computeStyleTests(); + return pixelPositionVal; + }, + reliableMarginLeft: function() { + computeStyleTests(); + return reliableMarginLeftVal; + }, + scrollboxSize: function() { + computeStyleTests(); + return scrollboxSizeVal; + }, + + // Support: IE 9 - 11+, Edge 15 - 18+ + // IE/Edge misreport `getComputedStyle` of table rows with width/height + // set in CSS while `offset*` properties report correct values. + // Behavior in IE 9 is more subtle than in newer versions & it passes + // some versions of this test; make sure not to make it pass there! + // + // Support: Firefox 70+ + // Only Firefox includes border widths + // in computed dimensions. (gh-4529) + reliableTrDimensions: function() { + var table, tr, trChild, trStyle; + if ( reliableTrDimensionsVal == null ) { + table = document.createElement( "table" ); + tr = document.createElement( "tr" ); + trChild = document.createElement( "div" ); + + table.style.cssText = "position:absolute;left:-11111px;border-collapse:separate"; + tr.style.cssText = "border:1px solid"; + + // Support: Chrome 86+ + // Height set through cssText does not get applied. + // Computed height then comes back as 0. + tr.style.height = "1px"; + trChild.style.height = "9px"; + + // Support: Android 8 Chrome 86+ + // In our bodyBackground.html iframe, + // display for all div elements is set to "inline", + // which causes a problem only in Android 8 Chrome 86. + // Ensuring the div is display: block + // gets around this issue. + trChild.style.display = "block"; + + documentElement + .appendChild( table ) + .appendChild( tr ) + .appendChild( trChild ); + + trStyle = window.getComputedStyle( tr ); + reliableTrDimensionsVal = ( parseInt( trStyle.height, 10 ) + + parseInt( trStyle.borderTopWidth, 10 ) + + parseInt( trStyle.borderBottomWidth, 10 ) ) === tr.offsetHeight; + + documentElement.removeChild( table ); + } + return reliableTrDimensionsVal; + } + } ); +} )(); + + +function curCSS( elem, name, computed ) { + var width, minWidth, maxWidth, ret, + + // Support: Firefox 51+ + // Retrieving style before computed somehow + // fixes an issue with getting wrong values + // on detached elements + style = elem.style; + + computed = computed || getStyles( elem ); + + // getPropertyValue is needed for: + // .css('filter') (IE 9 only, #12537) + // .css('--customProperty) (#3144) + if ( computed ) { + ret = computed.getPropertyValue( name ) || computed[ name ]; + + if ( ret === "" && !isAttached( elem ) ) { + ret = jQuery.style( elem, name ); + } + + // A tribute to the "awesome hack by Dean Edwards" + // Android Browser returns percentage for some values, + // but width seems to be reliably pixels. + // This is against the CSSOM draft spec: + // https://drafts.csswg.org/cssom/#resolved-values + if ( !support.pixelBoxStyles() && rnumnonpx.test( ret ) && rboxStyle.test( name ) ) { + + // Remember the original values + width = style.width; + minWidth = style.minWidth; + maxWidth = style.maxWidth; + + // Put in the new values to get a computed value out + style.minWidth = style.maxWidth = style.width = ret; + ret = computed.width; + + // Revert the changed values + style.width = width; + style.minWidth = minWidth; + style.maxWidth = maxWidth; + } + } + + return ret !== undefined ? + + // Support: IE <=9 - 11 only + // IE returns zIndex value as an integer. + ret + "" : + ret; +} + + +function addGetHookIf( conditionFn, hookFn ) { + + // Define the hook, we'll check on the first run if it's really needed. + return { + get: function() { + if ( conditionFn() ) { + + // Hook not needed (or it's not possible to use it due + // to missing dependency), remove it. + delete this.get; + return; + } + + // Hook needed; redefine it so that the support test is not executed again. + return ( this.get = hookFn ).apply( this, arguments ); + } + }; +} + + +var cssPrefixes = [ "Webkit", "Moz", "ms" ], + emptyStyle = document.createElement( "div" ).style, + vendorProps = {}; + +// Return a vendor-prefixed property or undefined +function vendorPropName( name ) { + + // Check for vendor prefixed names + var capName = name[ 0 ].toUpperCase() + name.slice( 1 ), + i = cssPrefixes.length; + + while ( i-- ) { + name = cssPrefixes[ i ] + capName; + if ( name in emptyStyle ) { + return name; + } + } +} + +// Return a potentially-mapped jQuery.cssProps or vendor prefixed property +function finalPropName( name ) { + var final = jQuery.cssProps[ name ] || vendorProps[ name ]; + + if ( final ) { + return final; + } + if ( name in emptyStyle ) { + return name; + } + return vendorProps[ name ] = vendorPropName( name ) || name; +} + + +var + + // Swappable if display is none or starts with table + // except "table", "table-cell", or "table-caption" + // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display + rdisplayswap = /^(none|table(?!-c[ea]).+)/, + rcustomProp = /^--/, + cssShow = { position: "absolute", visibility: "hidden", display: "block" }, + cssNormalTransform = { + letterSpacing: "0", + fontWeight: "400" + }; + +function setPositiveNumber( _elem, value, subtract ) { + + // Any relative (+/-) values have already been + // normalized at this point + var matches = rcssNum.exec( value ); + return matches ? + + // Guard against undefined "subtract", e.g., when used as in cssHooks + Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) : + value; +} + +function boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computedVal ) { + var i = dimension === "width" ? 1 : 0, + extra = 0, + delta = 0; + + // Adjustment may not be necessary + if ( box === ( isBorderBox ? "border" : "content" ) ) { + return 0; + } + + for ( ; i < 4; i += 2 ) { + + // Both box models exclude margin + if ( box === "margin" ) { + delta += jQuery.css( elem, box + cssExpand[ i ], true, styles ); + } + + // If we get here with a content-box, we're seeking "padding" or "border" or "margin" + if ( !isBorderBox ) { + + // Add padding + delta += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + + // For "border" or "margin", add border + if ( box !== "padding" ) { + delta += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + + // But still keep track of it otherwise + } else { + extra += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + + // If we get here with a border-box (content + padding + border), we're seeking "content" or + // "padding" or "margin" + } else { + + // For "content", subtract padding + if ( box === "content" ) { + delta -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + } + + // For "content" or "padding", subtract border + if ( box !== "margin" ) { + delta -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } + } + + // Account for positive content-box scroll gutter when requested by providing computedVal + if ( !isBorderBox && computedVal >= 0 ) { + + // offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border + // Assuming integer scroll gutter, subtract the rest and round down + delta += Math.max( 0, Math.ceil( + elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - + computedVal - + delta - + extra - + 0.5 + + // If offsetWidth/offsetHeight is unknown, then we can't determine content-box scroll gutter + // Use an explicit zero to avoid NaN (gh-3964) + ) ) || 0; + } + + return delta; +} + +function getWidthOrHeight( elem, dimension, extra ) { + + // Start with computed style + var styles = getStyles( elem ), + + // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-4322). + // Fake content-box until we know it's needed to know the true value. + boxSizingNeeded = !support.boxSizingReliable() || extra, + isBorderBox = boxSizingNeeded && + jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + valueIsBorderBox = isBorderBox, + + val = curCSS( elem, dimension, styles ), + offsetProp = "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ); + + // Support: Firefox <=54 + // Return a confounding non-pixel value or feign ignorance, as appropriate. + if ( rnumnonpx.test( val ) ) { + if ( !extra ) { + return val; + } + val = "auto"; + } + + + // Support: IE 9 - 11 only + // Use offsetWidth/offsetHeight for when box sizing is unreliable. + // In those cases, the computed value can be trusted to be border-box. + if ( ( !support.boxSizingReliable() && isBorderBox || + + // Support: IE 10 - 11+, Edge 15 - 18+ + // IE/Edge misreport `getComputedStyle` of table rows with width/height + // set in CSS while `offset*` properties report correct values. + // Interestingly, in some cases IE 9 doesn't suffer from this issue. + !support.reliableTrDimensions() && nodeName( elem, "tr" ) || + + // Fall back to offsetWidth/offsetHeight when value is "auto" + // This happens for inline elements with no explicit setting (gh-3571) + val === "auto" || + + // Support: Android <=4.1 - 4.3 only + // Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602) + !parseFloat( val ) && jQuery.css( elem, "display", false, styles ) === "inline" ) && + + // Make sure the element is visible & connected + elem.getClientRects().length ) { + + isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; + + // Where available, offsetWidth/offsetHeight approximate border box dimensions. + // Where not available (e.g., SVG), assume unreliable box-sizing and interpret the + // retrieved value as a content box dimension. + valueIsBorderBox = offsetProp in elem; + if ( valueIsBorderBox ) { + val = elem[ offsetProp ]; + } + } + + // Normalize "" and auto + val = parseFloat( val ) || 0; + + // Adjust for the element's box model + return ( val + + boxModelAdjustment( + elem, + dimension, + extra || ( isBorderBox ? "border" : "content" ), + valueIsBorderBox, + styles, + + // Provide the current computed size to request scroll gutter calculation (gh-3589) + val + ) + ) + "px"; +} + +jQuery.extend( { + + // Add in style property hooks for overriding the default + // behavior of getting and setting a style property + cssHooks: { + opacity: { + get: function( elem, computed ) { + if ( computed ) { + + // We should always get a number back from opacity + var ret = curCSS( elem, "opacity" ); + return ret === "" ? "1" : ret; + } + } + } + }, + + // Don't automatically add "px" to these possibly-unitless properties + cssNumber: { + "animationIterationCount": true, + "columnCount": true, + "fillOpacity": true, + "flexGrow": true, + "flexShrink": true, + "fontWeight": true, + "gridArea": true, + "gridColumn": true, + "gridColumnEnd": true, + "gridColumnStart": true, + "gridRow": true, + "gridRowEnd": true, + "gridRowStart": true, + "lineHeight": true, + "opacity": true, + "order": true, + "orphans": true, + "widows": true, + "zIndex": true, + "zoom": true + }, + + // Add in properties whose names you wish to fix before + // setting or getting the value + cssProps: {}, + + // Get and set the style property on a DOM Node + style: function( elem, name, value, extra ) { + + // Don't set styles on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { + return; + } + + // Make sure that we're working with the right name + var ret, type, hooks, + origName = camelCase( name ), + isCustomProp = rcustomProp.test( name ), + style = elem.style; + + // Make sure that we're working with the right name. We don't + // want to query the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Gets hook for the prefixed version, then unprefixed version + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // Check if we're setting a value + if ( value !== undefined ) { + type = typeof value; + + // Convert "+=" or "-=" to relative numbers (#7345) + if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) { + value = adjustCSS( elem, name, ret ); + + // Fixes bug #9237 + type = "number"; + } + + // Make sure that null and NaN values aren't set (#7116) + if ( value == null || value !== value ) { + return; + } + + // If a number was passed in, add the unit (except for certain CSS properties) + // The isCustomProp check can be removed in jQuery 4.0 when we only auto-append + // "px" to a few hardcoded values. + if ( type === "number" && !isCustomProp ) { + value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" ); + } + + // background-* props affect original clone's values + if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) { + style[ name ] = "inherit"; + } + + // If a hook was provided, use that value, otherwise just set the specified value + if ( !hooks || !( "set" in hooks ) || + ( value = hooks.set( elem, value, extra ) ) !== undefined ) { + + if ( isCustomProp ) { + style.setProperty( name, value ); + } else { + style[ name ] = value; + } + } + + } else { + + // If a hook was provided get the non-computed value from there + if ( hooks && "get" in hooks && + ( ret = hooks.get( elem, false, extra ) ) !== undefined ) { + + return ret; + } + + // Otherwise just get the value from the style object + return style[ name ]; + } + }, + + css: function( elem, name, extra, styles ) { + var val, num, hooks, + origName = camelCase( name ), + isCustomProp = rcustomProp.test( name ); + + // Make sure that we're working with the right name. We don't + // want to modify the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Try prefixed name followed by the unprefixed name + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // If a hook was provided get the computed value from there + if ( hooks && "get" in hooks ) { + val = hooks.get( elem, true, extra ); + } + + // Otherwise, if a way to get the computed value exists, use that + if ( val === undefined ) { + val = curCSS( elem, name, styles ); + } + + // Convert "normal" to computed value + if ( val === "normal" && name in cssNormalTransform ) { + val = cssNormalTransform[ name ]; + } + + // Make numeric if forced or a qualifier was provided and val looks numeric + if ( extra === "" || extra ) { + num = parseFloat( val ); + return extra === true || isFinite( num ) ? num || 0 : val; + } + + return val; + } +} ); + +jQuery.each( [ "height", "width" ], function( _i, dimension ) { + jQuery.cssHooks[ dimension ] = { + get: function( elem, computed, extra ) { + if ( computed ) { + + // Certain elements can have dimension info if we invisibly show them + // but it must have a current display style that would benefit + return rdisplayswap.test( jQuery.css( elem, "display" ) ) && + + // Support: Safari 8+ + // Table columns in Safari have non-zero offsetWidth & zero + // getBoundingClientRect().width unless display is changed. + // Support: IE <=11 only + // Running getBoundingClientRect on a disconnected node + // in IE throws an error. + ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? + swap( elem, cssShow, function() { + return getWidthOrHeight( elem, dimension, extra ); + } ) : + getWidthOrHeight( elem, dimension, extra ); + } + }, + + set: function( elem, value, extra ) { + var matches, + styles = getStyles( elem ), + + // Only read styles.position if the test has a chance to fail + // to avoid forcing a reflow. + scrollboxSizeBuggy = !support.scrollboxSize() && + styles.position === "absolute", + + // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-3991) + boxSizingNeeded = scrollboxSizeBuggy || extra, + isBorderBox = boxSizingNeeded && + jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + subtract = extra ? + boxModelAdjustment( + elem, + dimension, + extra, + isBorderBox, + styles + ) : + 0; + + // Account for unreliable border-box dimensions by comparing offset* to computed and + // faking a content-box to get border and padding (gh-3699) + if ( isBorderBox && scrollboxSizeBuggy ) { + subtract -= Math.ceil( + elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - + parseFloat( styles[ dimension ] ) - + boxModelAdjustment( elem, dimension, "border", false, styles ) - + 0.5 + ); + } + + // Convert to pixels if value adjustment is needed + if ( subtract && ( matches = rcssNum.exec( value ) ) && + ( matches[ 3 ] || "px" ) !== "px" ) { + + elem.style[ dimension ] = value; + value = jQuery.css( elem, dimension ); + } + + return setPositiveNumber( elem, value, subtract ); + } + }; +} ); + +jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, + function( elem, computed ) { + if ( computed ) { + return ( parseFloat( curCSS( elem, "marginLeft" ) ) || + elem.getBoundingClientRect().left - + swap( elem, { marginLeft: 0 }, function() { + return elem.getBoundingClientRect().left; + } ) + ) + "px"; + } + } +); + +// These hooks are used by animate to expand properties +jQuery.each( { + margin: "", + padding: "", + border: "Width" +}, function( prefix, suffix ) { + jQuery.cssHooks[ prefix + suffix ] = { + expand: function( value ) { + var i = 0, + expanded = {}, + + // Assumes a single number if not a string + parts = typeof value === "string" ? value.split( " " ) : [ value ]; + + for ( ; i < 4; i++ ) { + expanded[ prefix + cssExpand[ i ] + suffix ] = + parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; + } + + return expanded; + } + }; + + if ( prefix !== "margin" ) { + jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; + } +} ); + +jQuery.fn.extend( { + css: function( name, value ) { + return access( this, function( elem, name, value ) { + var styles, len, + map = {}, + i = 0; + + if ( Array.isArray( name ) ) { + styles = getStyles( elem ); + len = name.length; + + for ( ; i < len; i++ ) { + map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); + } + + return map; + } + + return value !== undefined ? + jQuery.style( elem, name, value ) : + jQuery.css( elem, name ); + }, name, value, arguments.length > 1 ); + } +} ); + + +function Tween( elem, options, prop, end, easing ) { + return new Tween.prototype.init( elem, options, prop, end, easing ); +} +jQuery.Tween = Tween; + +Tween.prototype = { + constructor: Tween, + init: function( elem, options, prop, end, easing, unit ) { + this.elem = elem; + this.prop = prop; + this.easing = easing || jQuery.easing._default; + this.options = options; + this.start = this.now = this.cur(); + this.end = end; + this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); + }, + cur: function() { + var hooks = Tween.propHooks[ this.prop ]; + + return hooks && hooks.get ? + hooks.get( this ) : + Tween.propHooks._default.get( this ); + }, + run: function( percent ) { + var eased, + hooks = Tween.propHooks[ this.prop ]; + + if ( this.options.duration ) { + this.pos = eased = jQuery.easing[ this.easing ]( + percent, this.options.duration * percent, 0, 1, this.options.duration + ); + } else { + this.pos = eased = percent; + } + this.now = ( this.end - this.start ) * eased + this.start; + + if ( this.options.step ) { + this.options.step.call( this.elem, this.now, this ); + } + + if ( hooks && hooks.set ) { + hooks.set( this ); + } else { + Tween.propHooks._default.set( this ); + } + return this; + } +}; + +Tween.prototype.init.prototype = Tween.prototype; + +Tween.propHooks = { + _default: { + get: function( tween ) { + var result; + + // Use a property on the element directly when it is not a DOM element, + // or when there is no matching style property that exists. + if ( tween.elem.nodeType !== 1 || + tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) { + return tween.elem[ tween.prop ]; + } + + // Passing an empty string as a 3rd parameter to .css will automatically + // attempt a parseFloat and fallback to a string if the parse fails. + // Simple values such as "10px" are parsed to Float; + // complex values such as "rotate(1rad)" are returned as-is. + result = jQuery.css( tween.elem, tween.prop, "" ); + + // Empty strings, null, undefined and "auto" are converted to 0. + return !result || result === "auto" ? 0 : result; + }, + set: function( tween ) { + + // Use step hook for back compat. + // Use cssHook if its there. + // Use .style if available and use plain properties where available. + if ( jQuery.fx.step[ tween.prop ] ) { + jQuery.fx.step[ tween.prop ]( tween ); + } else if ( tween.elem.nodeType === 1 && ( + jQuery.cssHooks[ tween.prop ] || + tween.elem.style[ finalPropName( tween.prop ) ] != null ) ) { + jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); + } else { + tween.elem[ tween.prop ] = tween.now; + } + } + } +}; + +// Support: IE <=9 only +// Panic based approach to setting things on disconnected nodes +Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { + set: function( tween ) { + if ( tween.elem.nodeType && tween.elem.parentNode ) { + tween.elem[ tween.prop ] = tween.now; + } + } +}; + +jQuery.easing = { + linear: function( p ) { + return p; + }, + swing: function( p ) { + return 0.5 - Math.cos( p * Math.PI ) / 2; + }, + _default: "swing" +}; + +jQuery.fx = Tween.prototype.init; + +// Back compat <1.8 extension point +jQuery.fx.step = {}; + + + + +var + fxNow, inProgress, + rfxtypes = /^(?:toggle|show|hide)$/, + rrun = /queueHooks$/; + +function schedule() { + if ( inProgress ) { + if ( document.hidden === false && window.requestAnimationFrame ) { + window.requestAnimationFrame( schedule ); + } else { + window.setTimeout( schedule, jQuery.fx.interval ); + } + + jQuery.fx.tick(); + } +} + +// Animations created synchronously will run synchronously +function createFxNow() { + window.setTimeout( function() { + fxNow = undefined; + } ); + return ( fxNow = Date.now() ); +} + +// Generate parameters to create a standard animation +function genFx( type, includeWidth ) { + var which, + i = 0, + attrs = { height: type }; + + // If we include width, step value is 1 to do all cssExpand values, + // otherwise step value is 2 to skip over Left and Right + includeWidth = includeWidth ? 1 : 0; + for ( ; i < 4; i += 2 - includeWidth ) { + which = cssExpand[ i ]; + attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; + } + + if ( includeWidth ) { + attrs.opacity = attrs.width = type; + } + + return attrs; +} + +function createTween( value, prop, animation ) { + var tween, + collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ), + index = 0, + length = collection.length; + for ( ; index < length; index++ ) { + if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) { + + // We're done with this property + return tween; + } + } +} + +function defaultPrefilter( elem, props, opts ) { + var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display, + isBox = "width" in props || "height" in props, + anim = this, + orig = {}, + style = elem.style, + hidden = elem.nodeType && isHiddenWithinTree( elem ), + dataShow = dataPriv.get( elem, "fxshow" ); + + // Queue-skipping animations hijack the fx hooks + if ( !opts.queue ) { + hooks = jQuery._queueHooks( elem, "fx" ); + if ( hooks.unqueued == null ) { + hooks.unqueued = 0; + oldfire = hooks.empty.fire; + hooks.empty.fire = function() { + if ( !hooks.unqueued ) { + oldfire(); + } + }; + } + hooks.unqueued++; + + anim.always( function() { + + // Ensure the complete handler is called before this completes + anim.always( function() { + hooks.unqueued--; + if ( !jQuery.queue( elem, "fx" ).length ) { + hooks.empty.fire(); + } + } ); + } ); + } + + // Detect show/hide animations + for ( prop in props ) { + value = props[ prop ]; + if ( rfxtypes.test( value ) ) { + delete props[ prop ]; + toggle = toggle || value === "toggle"; + if ( value === ( hidden ? "hide" : "show" ) ) { + + // Pretend to be hidden if this is a "show" and + // there is still data from a stopped show/hide + if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) { + hidden = true; + + // Ignore all other no-op show/hide data + } else { + continue; + } + } + orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop ); + } + } + + // Bail out if this is a no-op like .hide().hide() + propTween = !jQuery.isEmptyObject( props ); + if ( !propTween && jQuery.isEmptyObject( orig ) ) { + return; + } + + // Restrict "overflow" and "display" styles during box animations + if ( isBox && elem.nodeType === 1 ) { + + // Support: IE <=9 - 11, Edge 12 - 15 + // Record all 3 overflow attributes because IE does not infer the shorthand + // from identically-valued overflowX and overflowY and Edge just mirrors + // the overflowX value there. + opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; + + // Identify a display type, preferring old show/hide data over the CSS cascade + restoreDisplay = dataShow && dataShow.display; + if ( restoreDisplay == null ) { + restoreDisplay = dataPriv.get( elem, "display" ); + } + display = jQuery.css( elem, "display" ); + if ( display === "none" ) { + if ( restoreDisplay ) { + display = restoreDisplay; + } else { + + // Get nonempty value(s) by temporarily forcing visibility + showHide( [ elem ], true ); + restoreDisplay = elem.style.display || restoreDisplay; + display = jQuery.css( elem, "display" ); + showHide( [ elem ] ); + } + } + + // Animate inline elements as inline-block + if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) { + if ( jQuery.css( elem, "float" ) === "none" ) { + + // Restore the original display value at the end of pure show/hide animations + if ( !propTween ) { + anim.done( function() { + style.display = restoreDisplay; + } ); + if ( restoreDisplay == null ) { + display = style.display; + restoreDisplay = display === "none" ? "" : display; + } + } + style.display = "inline-block"; + } + } + } + + if ( opts.overflow ) { + style.overflow = "hidden"; + anim.always( function() { + style.overflow = opts.overflow[ 0 ]; + style.overflowX = opts.overflow[ 1 ]; + style.overflowY = opts.overflow[ 2 ]; + } ); + } + + // Implement show/hide animations + propTween = false; + for ( prop in orig ) { + + // General show/hide setup for this element animation + if ( !propTween ) { + if ( dataShow ) { + if ( "hidden" in dataShow ) { + hidden = dataShow.hidden; + } + } else { + dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } ); + } + + // Store hidden/visible for toggle so `.stop().toggle()` "reverses" + if ( toggle ) { + dataShow.hidden = !hidden; + } + + // Show elements before animating them + if ( hidden ) { + showHide( [ elem ], true ); + } + + /* eslint-disable no-loop-func */ + + anim.done( function() { + + /* eslint-enable no-loop-func */ + + // The final step of a "hide" animation is actually hiding the element + if ( !hidden ) { + showHide( [ elem ] ); + } + dataPriv.remove( elem, "fxshow" ); + for ( prop in orig ) { + jQuery.style( elem, prop, orig[ prop ] ); + } + } ); + } + + // Per-property setup + propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim ); + if ( !( prop in dataShow ) ) { + dataShow[ prop ] = propTween.start; + if ( hidden ) { + propTween.end = propTween.start; + propTween.start = 0; + } + } + } +} + +function propFilter( props, specialEasing ) { + var index, name, easing, value, hooks; + + // camelCase, specialEasing and expand cssHook pass + for ( index in props ) { + name = camelCase( index ); + easing = specialEasing[ name ]; + value = props[ index ]; + if ( Array.isArray( value ) ) { + easing = value[ 1 ]; + value = props[ index ] = value[ 0 ]; + } + + if ( index !== name ) { + props[ name ] = value; + delete props[ index ]; + } + + hooks = jQuery.cssHooks[ name ]; + if ( hooks && "expand" in hooks ) { + value = hooks.expand( value ); + delete props[ name ]; + + // Not quite $.extend, this won't overwrite existing keys. + // Reusing 'index' because we have the correct "name" + for ( index in value ) { + if ( !( index in props ) ) { + props[ index ] = value[ index ]; + specialEasing[ index ] = easing; + } + } + } else { + specialEasing[ name ] = easing; + } + } +} + +function Animation( elem, properties, options ) { + var result, + stopped, + index = 0, + length = Animation.prefilters.length, + deferred = jQuery.Deferred().always( function() { + + // Don't match elem in the :animated selector + delete tick.elem; + } ), + tick = function() { + if ( stopped ) { + return false; + } + var currentTime = fxNow || createFxNow(), + remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), + + // Support: Android 2.3 only + // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497) + temp = remaining / animation.duration || 0, + percent = 1 - temp, + index = 0, + length = animation.tweens.length; + + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( percent ); + } + + deferred.notifyWith( elem, [ animation, percent, remaining ] ); + + // If there's more to do, yield + if ( percent < 1 && length ) { + return remaining; + } + + // If this was an empty animation, synthesize a final progress notification + if ( !length ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + } + + // Resolve the animation and report its conclusion + deferred.resolveWith( elem, [ animation ] ); + return false; + }, + animation = deferred.promise( { + elem: elem, + props: jQuery.extend( {}, properties ), + opts: jQuery.extend( true, { + specialEasing: {}, + easing: jQuery.easing._default + }, options ), + originalProperties: properties, + originalOptions: options, + startTime: fxNow || createFxNow(), + duration: options.duration, + tweens: [], + createTween: function( prop, end ) { + var tween = jQuery.Tween( elem, animation.opts, prop, end, + animation.opts.specialEasing[ prop ] || animation.opts.easing ); + animation.tweens.push( tween ); + return tween; + }, + stop: function( gotoEnd ) { + var index = 0, + + // If we are going to the end, we want to run all the tweens + // otherwise we skip this part + length = gotoEnd ? animation.tweens.length : 0; + if ( stopped ) { + return this; + } + stopped = true; + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( 1 ); + } + + // Resolve when we played the last frame; otherwise, reject + if ( gotoEnd ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + deferred.resolveWith( elem, [ animation, gotoEnd ] ); + } else { + deferred.rejectWith( elem, [ animation, gotoEnd ] ); + } + return this; + } + } ), + props = animation.props; + + propFilter( props, animation.opts.specialEasing ); + + for ( ; index < length; index++ ) { + result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts ); + if ( result ) { + if ( isFunction( result.stop ) ) { + jQuery._queueHooks( animation.elem, animation.opts.queue ).stop = + result.stop.bind( result ); + } + return result; + } + } + + jQuery.map( props, createTween, animation ); + + if ( isFunction( animation.opts.start ) ) { + animation.opts.start.call( elem, animation ); + } + + // Attach callbacks from options + animation + .progress( animation.opts.progress ) + .done( animation.opts.done, animation.opts.complete ) + .fail( animation.opts.fail ) + .always( animation.opts.always ); + + jQuery.fx.timer( + jQuery.extend( tick, { + elem: elem, + anim: animation, + queue: animation.opts.queue + } ) + ); + + return animation; +} + +jQuery.Animation = jQuery.extend( Animation, { + + tweeners: { + "*": [ function( prop, value ) { + var tween = this.createTween( prop, value ); + adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween ); + return tween; + } ] + }, + + tweener: function( props, callback ) { + if ( isFunction( props ) ) { + callback = props; + props = [ "*" ]; + } else { + props = props.match( rnothtmlwhite ); + } + + var prop, + index = 0, + length = props.length; + + for ( ; index < length; index++ ) { + prop = props[ index ]; + Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || []; + Animation.tweeners[ prop ].unshift( callback ); + } + }, + + prefilters: [ defaultPrefilter ], + + prefilter: function( callback, prepend ) { + if ( prepend ) { + Animation.prefilters.unshift( callback ); + } else { + Animation.prefilters.push( callback ); + } + } +} ); + +jQuery.speed = function( speed, easing, fn ) { + var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { + complete: fn || !fn && easing || + isFunction( speed ) && speed, + duration: speed, + easing: fn && easing || easing && !isFunction( easing ) && easing + }; + + // Go to the end state if fx are off + if ( jQuery.fx.off ) { + opt.duration = 0; + + } else { + if ( typeof opt.duration !== "number" ) { + if ( opt.duration in jQuery.fx.speeds ) { + opt.duration = jQuery.fx.speeds[ opt.duration ]; + + } else { + opt.duration = jQuery.fx.speeds._default; + } + } + } + + // Normalize opt.queue - true/undefined/null -> "fx" + if ( opt.queue == null || opt.queue === true ) { + opt.queue = "fx"; + } + + // Queueing + opt.old = opt.complete; + + opt.complete = function() { + if ( isFunction( opt.old ) ) { + opt.old.call( this ); + } + + if ( opt.queue ) { + jQuery.dequeue( this, opt.queue ); + } + }; + + return opt; +}; + +jQuery.fn.extend( { + fadeTo: function( speed, to, easing, callback ) { + + // Show any hidden elements after setting opacity to 0 + return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show() + + // Animate to the value specified + .end().animate( { opacity: to }, speed, easing, callback ); + }, + animate: function( prop, speed, easing, callback ) { + var empty = jQuery.isEmptyObject( prop ), + optall = jQuery.speed( speed, easing, callback ), + doAnimation = function() { + + // Operate on a copy of prop so per-property easing won't be lost + var anim = Animation( this, jQuery.extend( {}, prop ), optall ); + + // Empty animations, or finishing resolves immediately + if ( empty || dataPriv.get( this, "finish" ) ) { + anim.stop( true ); + } + }; + + doAnimation.finish = doAnimation; + + return empty || optall.queue === false ? + this.each( doAnimation ) : + this.queue( optall.queue, doAnimation ); + }, + stop: function( type, clearQueue, gotoEnd ) { + var stopQueue = function( hooks ) { + var stop = hooks.stop; + delete hooks.stop; + stop( gotoEnd ); + }; + + if ( typeof type !== "string" ) { + gotoEnd = clearQueue; + clearQueue = type; + type = undefined; + } + if ( clearQueue ) { + this.queue( type || "fx", [] ); + } + + return this.each( function() { + var dequeue = true, + index = type != null && type + "queueHooks", + timers = jQuery.timers, + data = dataPriv.get( this ); + + if ( index ) { + if ( data[ index ] && data[ index ].stop ) { + stopQueue( data[ index ] ); + } + } else { + for ( index in data ) { + if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { + stopQueue( data[ index ] ); + } + } + } + + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && + ( type == null || timers[ index ].queue === type ) ) { + + timers[ index ].anim.stop( gotoEnd ); + dequeue = false; + timers.splice( index, 1 ); + } + } + + // Start the next in the queue if the last step wasn't forced. + // Timers currently will call their complete callbacks, which + // will dequeue but only if they were gotoEnd. + if ( dequeue || !gotoEnd ) { + jQuery.dequeue( this, type ); + } + } ); + }, + finish: function( type ) { + if ( type !== false ) { + type = type || "fx"; + } + return this.each( function() { + var index, + data = dataPriv.get( this ), + queue = data[ type + "queue" ], + hooks = data[ type + "queueHooks" ], + timers = jQuery.timers, + length = queue ? queue.length : 0; + + // Enable finishing flag on private data + data.finish = true; + + // Empty the queue first + jQuery.queue( this, type, [] ); + + if ( hooks && hooks.stop ) { + hooks.stop.call( this, true ); + } + + // Look for any active animations, and finish them + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && timers[ index ].queue === type ) { + timers[ index ].anim.stop( true ); + timers.splice( index, 1 ); + } + } + + // Look for any animations in the old queue and finish them + for ( index = 0; index < length; index++ ) { + if ( queue[ index ] && queue[ index ].finish ) { + queue[ index ].finish.call( this ); + } + } + + // Turn off finishing flag + delete data.finish; + } ); + } +} ); + +jQuery.each( [ "toggle", "show", "hide" ], function( _i, name ) { + var cssFn = jQuery.fn[ name ]; + jQuery.fn[ name ] = function( speed, easing, callback ) { + return speed == null || typeof speed === "boolean" ? + cssFn.apply( this, arguments ) : + this.animate( genFx( name, true ), speed, easing, callback ); + }; +} ); + +// Generate shortcuts for custom animations +jQuery.each( { + slideDown: genFx( "show" ), + slideUp: genFx( "hide" ), + slideToggle: genFx( "toggle" ), + fadeIn: { opacity: "show" }, + fadeOut: { opacity: "hide" }, + fadeToggle: { opacity: "toggle" } +}, function( name, props ) { + jQuery.fn[ name ] = function( speed, easing, callback ) { + return this.animate( props, speed, easing, callback ); + }; +} ); + +jQuery.timers = []; +jQuery.fx.tick = function() { + var timer, + i = 0, + timers = jQuery.timers; + + fxNow = Date.now(); + + for ( ; i < timers.length; i++ ) { + timer = timers[ i ]; + + // Run the timer and safely remove it when done (allowing for external removal) + if ( !timer() && timers[ i ] === timer ) { + timers.splice( i--, 1 ); + } + } + + if ( !timers.length ) { + jQuery.fx.stop(); + } + fxNow = undefined; +}; + +jQuery.fx.timer = function( timer ) { + jQuery.timers.push( timer ); + jQuery.fx.start(); +}; + +jQuery.fx.interval = 13; +jQuery.fx.start = function() { + if ( inProgress ) { + return; + } + + inProgress = true; + schedule(); +}; + +jQuery.fx.stop = function() { + inProgress = null; +}; + +jQuery.fx.speeds = { + slow: 600, + fast: 200, + + // Default speed + _default: 400 +}; + + +// Based off of the plugin by Clint Helfers, with permission. +// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/ +jQuery.fn.delay = function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; + type = type || "fx"; + + return this.queue( type, function( next, hooks ) { + var timeout = window.setTimeout( next, time ); + hooks.stop = function() { + window.clearTimeout( timeout ); + }; + } ); +}; + + +( function() { + var input = document.createElement( "input" ), + select = document.createElement( "select" ), + opt = select.appendChild( document.createElement( "option" ) ); + + input.type = "checkbox"; + + // Support: Android <=4.3 only + // Default value for a checkbox should be "on" + support.checkOn = input.value !== ""; + + // Support: IE <=11 only + // Must access selectedIndex to make default options select + support.optSelected = opt.selected; + + // Support: IE <=11 only + // An input loses its value after becoming a radio + input = document.createElement( "input" ); + input.value = "t"; + input.type = "radio"; + support.radioValue = input.value === "t"; +} )(); + + +var boolHook, + attrHandle = jQuery.expr.attrHandle; + +jQuery.fn.extend( { + attr: function( name, value ) { + return access( this, jQuery.attr, name, value, arguments.length > 1 ); + }, + + removeAttr: function( name ) { + return this.each( function() { + jQuery.removeAttr( this, name ); + } ); + } +} ); + +jQuery.extend( { + attr: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set attributes on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + // Fallback to prop when attributes are not supported + if ( typeof elem.getAttribute === "undefined" ) { + return jQuery.prop( elem, name, value ); + } + + // Attribute hooks are determined by the lowercase version + // Grab necessary hook if one is defined + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + hooks = jQuery.attrHooks[ name.toLowerCase() ] || + ( jQuery.expr.match.bool.test( name ) ? boolHook : undefined ); + } + + if ( value !== undefined ) { + if ( value === null ) { + jQuery.removeAttr( elem, name ); + return; + } + + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + elem.setAttribute( name, value + "" ); + return value; + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + ret = jQuery.find.attr( elem, name ); + + // Non-existent attributes return null, we normalize to undefined + return ret == null ? undefined : ret; + }, + + attrHooks: { + type: { + set: function( elem, value ) { + if ( !support.radioValue && value === "radio" && + nodeName( elem, "input" ) ) { + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + } + }, + + removeAttr: function( elem, value ) { + var name, + i = 0, + + // Attribute names can contain non-HTML whitespace characters + // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 + attrNames = value && value.match( rnothtmlwhite ); + + if ( attrNames && elem.nodeType === 1 ) { + while ( ( name = attrNames[ i++ ] ) ) { + elem.removeAttribute( name ); + } + } + } +} ); + +// Hooks for boolean attributes +boolHook = { + set: function( elem, value, name ) { + if ( value === false ) { + + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else { + elem.setAttribute( name, name ); + } + return name; + } +}; + +jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( _i, name ) { + var getter = attrHandle[ name ] || jQuery.find.attr; + + attrHandle[ name ] = function( elem, name, isXML ) { + var ret, handle, + lowercaseName = name.toLowerCase(); + + if ( !isXML ) { + + // Avoid an infinite loop by temporarily removing this function from the getter + handle = attrHandle[ lowercaseName ]; + attrHandle[ lowercaseName ] = ret; + ret = getter( elem, name, isXML ) != null ? + lowercaseName : + null; + attrHandle[ lowercaseName ] = handle; + } + return ret; + }; +} ); + + + + +var rfocusable = /^(?:input|select|textarea|button)$/i, + rclickable = /^(?:a|area)$/i; + +jQuery.fn.extend( { + prop: function( name, value ) { + return access( this, jQuery.prop, name, value, arguments.length > 1 ); + }, + + removeProp: function( name ) { + return this.each( function() { + delete this[ jQuery.propFix[ name ] || name ]; + } ); + } +} ); + +jQuery.extend( { + prop: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set properties on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; + } + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + return ( elem[ name ] = value ); + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + return elem[ name ]; + }, + + propHooks: { + tabIndex: { + get: function( elem ) { + + // Support: IE <=9 - 11 only + // elem.tabIndex doesn't always return the + // correct value when it hasn't been explicitly set + // https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + // Use proper attribute retrieval(#12072) + var tabindex = jQuery.find.attr( elem, "tabindex" ); + + if ( tabindex ) { + return parseInt( tabindex, 10 ); + } + + if ( + rfocusable.test( elem.nodeName ) || + rclickable.test( elem.nodeName ) && + elem.href + ) { + return 0; + } + + return -1; + } + } + }, + + propFix: { + "for": "htmlFor", + "class": "className" + } +} ); + +// Support: IE <=11 only +// Accessing the selectedIndex property +// forces the browser to respect setting selected +// on the option +// The getter ensures a default option is selected +// when in an optgroup +// eslint rule "no-unused-expressions" is disabled for this code +// since it considers such accessions noop +if ( !support.optSelected ) { + jQuery.propHooks.selected = { + get: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent && parent.parentNode ) { + parent.parentNode.selectedIndex; + } + return null; + }, + set: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent ) { + parent.selectedIndex; + + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + } + }; +} + +jQuery.each( [ + "tabIndex", + "readOnly", + "maxLength", + "cellSpacing", + "cellPadding", + "rowSpan", + "colSpan", + "useMap", + "frameBorder", + "contentEditable" +], function() { + jQuery.propFix[ this.toLowerCase() ] = this; +} ); + + + + + // Strip and collapse whitespace according to HTML spec + // https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace + function stripAndCollapse( value ) { + var tokens = value.match( rnothtmlwhite ) || []; + return tokens.join( " " ); + } + + +function getClass( elem ) { + return elem.getAttribute && elem.getAttribute( "class" ) || ""; +} + +function classesToArray( value ) { + if ( Array.isArray( value ) ) { + return value; + } + if ( typeof value === "string" ) { + return value.match( rnothtmlwhite ) || []; + } + return []; +} + +jQuery.fn.extend( { + addClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).addClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + classes = classesToArray( value ); + + if ( classes.length ) { + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + if ( cur.indexOf( " " + clazz + " " ) < 0 ) { + cur += clazz + " "; + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + removeClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + if ( !arguments.length ) { + return this.attr( "class", "" ); + } + + classes = classesToArray( value ); + + if ( classes.length ) { + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + + // This expression is here for better compressibility (see addClass) + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + + // Remove *all* instances + while ( cur.indexOf( " " + clazz + " " ) > -1 ) { + cur = cur.replace( " " + clazz + " ", " " ); + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value, + isValidValue = type === "string" || Array.isArray( value ); + + if ( typeof stateVal === "boolean" && isValidValue ) { + return stateVal ? this.addClass( value ) : this.removeClass( value ); + } + + if ( isFunction( value ) ) { + return this.each( function( i ) { + jQuery( this ).toggleClass( + value.call( this, i, getClass( this ), stateVal ), + stateVal + ); + } ); + } + + return this.each( function() { + var className, i, self, classNames; + + if ( isValidValue ) { + + // Toggle individual class names + i = 0; + self = jQuery( this ); + classNames = classesToArray( value ); + + while ( ( className = classNames[ i++ ] ) ) { + + // Check each className given, space separated list + if ( self.hasClass( className ) ) { + self.removeClass( className ); + } else { + self.addClass( className ); + } + } + + // Toggle whole class name + } else if ( value === undefined || type === "boolean" ) { + className = getClass( this ); + if ( className ) { + + // Store className if set + dataPriv.set( this, "__className__", className ); + } + + // If the element has a class name or if we're passed `false`, + // then remove the whole classname (if there was one, the above saved it). + // Otherwise bring back whatever was previously saved (if anything), + // falling back to the empty string if nothing was stored. + if ( this.setAttribute ) { + this.setAttribute( "class", + className || value === false ? + "" : + dataPriv.get( this, "__className__" ) || "" + ); + } + } + } ); + }, + + hasClass: function( selector ) { + var className, elem, + i = 0; + + className = " " + selector + " "; + while ( ( elem = this[ i++ ] ) ) { + if ( elem.nodeType === 1 && + ( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) { + return true; + } + } + + return false; + } +} ); + + + + +var rreturn = /\r/g; + +jQuery.fn.extend( { + val: function( value ) { + var hooks, ret, valueIsFunction, + elem = this[ 0 ]; + + if ( !arguments.length ) { + if ( elem ) { + hooks = jQuery.valHooks[ elem.type ] || + jQuery.valHooks[ elem.nodeName.toLowerCase() ]; + + if ( hooks && + "get" in hooks && + ( ret = hooks.get( elem, "value" ) ) !== undefined + ) { + return ret; + } + + ret = elem.value; + + // Handle most common string cases + if ( typeof ret === "string" ) { + return ret.replace( rreturn, "" ); + } + + // Handle cases where value is null/undef or number + return ret == null ? "" : ret; + } + + return; + } + + valueIsFunction = isFunction( value ); + + return this.each( function( i ) { + var val; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( valueIsFunction ) { + val = value.call( this, i, jQuery( this ).val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + + } else if ( typeof val === "number" ) { + val += ""; + + } else if ( Array.isArray( val ) ) { + val = jQuery.map( val, function( value ) { + return value == null ? "" : value + ""; + } ); + } + + hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; + + // If set returns undefined, fall back to normal setting + if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) { + this.value = val; + } + } ); + } +} ); + +jQuery.extend( { + valHooks: { + option: { + get: function( elem ) { + + var val = jQuery.find.attr( elem, "value" ); + return val != null ? + val : + + // Support: IE <=10 - 11 only + // option.text throws exceptions (#14686, #14858) + // Strip and collapse whitespace + // https://html.spec.whatwg.org/#strip-and-collapse-whitespace + stripAndCollapse( jQuery.text( elem ) ); + } + }, + select: { + get: function( elem ) { + var value, option, i, + options = elem.options, + index = elem.selectedIndex, + one = elem.type === "select-one", + values = one ? null : [], + max = one ? index + 1 : options.length; + + if ( index < 0 ) { + i = max; + + } else { + i = one ? index : 0; + } + + // Loop through all the selected options + for ( ; i < max; i++ ) { + option = options[ i ]; + + // Support: IE <=9 only + // IE8-9 doesn't update selected after form reset (#2551) + if ( ( option.selected || i === index ) && + + // Don't return options that are disabled or in a disabled optgroup + !option.disabled && + ( !option.parentNode.disabled || + !nodeName( option.parentNode, "optgroup" ) ) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + return values; + }, + + set: function( elem, value ) { + var optionSet, option, + options = elem.options, + values = jQuery.makeArray( value ), + i = options.length; + + while ( i-- ) { + option = options[ i ]; + + /* eslint-disable no-cond-assign */ + + if ( option.selected = + jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1 + ) { + optionSet = true; + } + + /* eslint-enable no-cond-assign */ + } + + // Force browsers to behave consistently when non-matching value is set + if ( !optionSet ) { + elem.selectedIndex = -1; + } + return values; + } + } + } +} ); + +// Radios and checkboxes getter/setter +jQuery.each( [ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + set: function( elem, value ) { + if ( Array.isArray( value ) ) { + return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 ); + } + } + }; + if ( !support.checkOn ) { + jQuery.valHooks[ this ].get = function( elem ) { + return elem.getAttribute( "value" ) === null ? "on" : elem.value; + }; + } +} ); + + + + +// Return jQuery for attributes-only inclusion + + +support.focusin = "onfocusin" in window; + + +var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, + stopPropagationCallback = function( e ) { + e.stopPropagation(); + }; + +jQuery.extend( jQuery.event, { + + trigger: function( event, data, elem, onlyHandlers ) { + + var i, cur, tmp, bubbleType, ontype, handle, special, lastElement, + eventPath = [ elem || document ], + type = hasOwn.call( event, "type" ) ? event.type : event, + namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; + + cur = lastElement = tmp = elem = elem || document; + + // Don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf( "." ) > -1 ) { + + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split( "." ); + type = namespaces.shift(); + namespaces.sort(); + } + ontype = type.indexOf( ":" ) < 0 && "on" + type; + + // Caller can pass in a jQuery.Event object, Object, or just an event type string + event = event[ jQuery.expando ] ? + event : + new jQuery.Event( type, typeof event === "object" && event ); + + // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) + event.isTrigger = onlyHandlers ? 2 : 3; + event.namespace = namespaces.join( "." ); + event.rnamespace = event.namespace ? + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : + null; + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data == null ? + [ event ] : + jQuery.makeArray( data, [ event ] ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + if ( !onlyHandlers && !special.noBubble && !isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + if ( !rfocusMorph.test( bubbleType + type ) ) { + cur = cur.parentNode; + } + for ( ; cur; cur = cur.parentNode ) { + eventPath.push( cur ); + tmp = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( tmp === ( elem.ownerDocument || document ) ) { + eventPath.push( tmp.defaultView || tmp.parentWindow || window ); + } + } + + // Fire handlers on the event path + i = 0; + while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { + lastElement = cur; + event.type = i > 1 ? + bubbleType : + special.bindType || type; + + // jQuery handler + handle = ( dataPriv.get( cur, "events" ) || Object.create( null ) )[ event.type ] && + dataPriv.get( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + + // Native handler + handle = ontype && cur[ ontype ]; + if ( handle && handle.apply && acceptData( cur ) ) { + event.result = handle.apply( cur, data ); + if ( event.result === false ) { + event.preventDefault(); + } + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( ( !special._default || + special._default.apply( eventPath.pop(), data ) === false ) && + acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name as the event. + // Don't do default actions on window, that's where global variables be (#6170) + if ( ontype && isFunction( elem[ type ] ) && !isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + tmp = elem[ ontype ]; + + if ( tmp ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + + if ( event.isPropagationStopped() ) { + lastElement.addEventListener( type, stopPropagationCallback ); + } + + elem[ type ](); + + if ( event.isPropagationStopped() ) { + lastElement.removeEventListener( type, stopPropagationCallback ); + } + + jQuery.event.triggered = undefined; + + if ( tmp ) { + elem[ ontype ] = tmp; + } + } + } + } + + return event.result; + }, + + // Piggyback on a donor event to simulate a different one + // Used only for `focus(in | out)` events + simulate: function( type, elem, event ) { + var e = jQuery.extend( + new jQuery.Event(), + event, + { + type: type, + isSimulated: true + } + ); + + jQuery.event.trigger( e, null, elem ); + } + +} ); + +jQuery.fn.extend( { + + trigger: function( type, data ) { + return this.each( function() { + jQuery.event.trigger( type, data, this ); + } ); + }, + triggerHandler: function( type, data ) { + var elem = this[ 0 ]; + if ( elem ) { + return jQuery.event.trigger( type, data, elem, true ); + } + } +} ); + + +// Support: Firefox <=44 +// Firefox doesn't have focus(in | out) events +// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 +// +// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1 +// focus(in | out) events fire after focus & blur events, +// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order +// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857 +if ( !support.focusin ) { + jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler on the document while someone wants focusin/focusout + var handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + + // Handle: regular nodes (via `this.ownerDocument`), window + // (via `this.document`) & document (via `this`). + var doc = this.ownerDocument || this.document || this, + attaches = dataPriv.access( doc, fix ); + + if ( !attaches ) { + doc.addEventListener( orig, handler, true ); + } + dataPriv.access( doc, fix, ( attaches || 0 ) + 1 ); + }, + teardown: function() { + var doc = this.ownerDocument || this.document || this, + attaches = dataPriv.access( doc, fix ) - 1; + + if ( !attaches ) { + doc.removeEventListener( orig, handler, true ); + dataPriv.remove( doc, fix ); + + } else { + dataPriv.access( doc, fix, attaches ); + } + } + }; + } ); +} +var location = window.location; + +var nonce = { guid: Date.now() }; + +var rquery = ( /\?/ ); + + + +// Cross-browser xml parsing +jQuery.parseXML = function( data ) { + var xml, parserErrorElem; + if ( !data || typeof data !== "string" ) { + return null; + } + + // Support: IE 9 - 11 only + // IE throws on parseFromString with invalid input. + try { + xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); + } catch ( e ) {} + + parserErrorElem = xml && xml.getElementsByTagName( "parsererror" )[ 0 ]; + if ( !xml || parserErrorElem ) { + jQuery.error( "Invalid XML: " + ( + parserErrorElem ? + jQuery.map( parserErrorElem.childNodes, function( el ) { + return el.textContent; + } ).join( "\n" ) : + data + ) ); + } + return xml; +}; + + +var + rbracket = /\[\]$/, + rCRLF = /\r?\n/g, + rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, + rsubmittable = /^(?:input|select|textarea|keygen)/i; + +function buildParams( prefix, obj, traditional, add ) { + var name; + + if ( Array.isArray( obj ) ) { + + // Serialize array item. + jQuery.each( obj, function( i, v ) { + if ( traditional || rbracket.test( prefix ) ) { + + // Treat each array item as a scalar. + add( prefix, v ); + + } else { + + // Item is non-scalar (array or object), encode its numeric index. + buildParams( + prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]", + v, + traditional, + add + ); + } + } ); + + } else if ( !traditional && toType( obj ) === "object" ) { + + // Serialize object item. + for ( name in obj ) { + buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); + } + + } else { + + // Serialize scalar item. + add( prefix, obj ); + } +} + +// Serialize an array of form elements or a set of +// key/values into a query string +jQuery.param = function( a, traditional ) { + var prefix, + s = [], + add = function( key, valueOrFunction ) { + + // If value is a function, invoke it and use its return value + var value = isFunction( valueOrFunction ) ? + valueOrFunction() : + valueOrFunction; + + s[ s.length ] = encodeURIComponent( key ) + "=" + + encodeURIComponent( value == null ? "" : value ); + }; + + if ( a == null ) { + return ""; + } + + // If an array was passed in, assume that it is an array of form elements. + if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { + + // Serialize the form elements + jQuery.each( a, function() { + add( this.name, this.value ); + } ); + + } else { + + // If traditional, encode the "old" way (the way 1.3.2 or older + // did it), otherwise encode params recursively. + for ( prefix in a ) { + buildParams( prefix, a[ prefix ], traditional, add ); + } + } + + // Return the resulting serialization + return s.join( "&" ); +}; + +jQuery.fn.extend( { + serialize: function() { + return jQuery.param( this.serializeArray() ); + }, + serializeArray: function() { + return this.map( function() { + + // Can add propHook for "elements" to filter or add form elements + var elements = jQuery.prop( this, "elements" ); + return elements ? jQuery.makeArray( elements ) : this; + } ).filter( function() { + var type = this.type; + + // Use .is( ":disabled" ) so that fieldset[disabled] works + return this.name && !jQuery( this ).is( ":disabled" ) && + rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && + ( this.checked || !rcheckableType.test( type ) ); + } ).map( function( _i, elem ) { + var val = jQuery( this ).val(); + + if ( val == null ) { + return null; + } + + if ( Array.isArray( val ) ) { + return jQuery.map( val, function( val ) { + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ); + } + + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ).get(); + } +} ); + + +var + r20 = /%20/g, + rhash = /#.*$/, + rantiCache = /([?&])_=[^&]*/, + rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg, + + // #7653, #8125, #8152: local protocol detection + rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, + rnoContent = /^(?:GET|HEAD)$/, + rprotocol = /^\/\//, + + /* Prefilters + * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) + * 2) These are called: + * - BEFORE asking for a transport + * - AFTER param serialization (s.data is a string if s.processData is true) + * 3) key is the dataType + * 4) the catchall symbol "*" can be used + * 5) execution will start with transport dataType and THEN continue down to "*" if needed + */ + prefilters = {}, + + /* Transports bindings + * 1) key is the dataType + * 2) the catchall symbol "*" can be used + * 3) selection will start with transport dataType and THEN go to "*" if needed + */ + transports = {}, + + // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression + allTypes = "*/".concat( "*" ), + + // Anchor tag for parsing the document origin + originAnchor = document.createElement( "a" ); + +originAnchor.href = location.href; + +// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport +function addToPrefiltersOrTransports( structure ) { + + // dataTypeExpression is optional and defaults to "*" + return function( dataTypeExpression, func ) { + + if ( typeof dataTypeExpression !== "string" ) { + func = dataTypeExpression; + dataTypeExpression = "*"; + } + + var dataType, + i = 0, + dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || []; + + if ( isFunction( func ) ) { + + // For each dataType in the dataTypeExpression + while ( ( dataType = dataTypes[ i++ ] ) ) { + + // Prepend if requested + if ( dataType[ 0 ] === "+" ) { + dataType = dataType.slice( 1 ) || "*"; + ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func ); + + // Otherwise append + } else { + ( structure[ dataType ] = structure[ dataType ] || [] ).push( func ); + } + } + } + }; +} + +// Base inspection function for prefilters and transports +function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) { + + var inspected = {}, + seekingTransport = ( structure === transports ); + + function inspect( dataType ) { + var selected; + inspected[ dataType ] = true; + jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) { + var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR ); + if ( typeof dataTypeOrTransport === "string" && + !seekingTransport && !inspected[ dataTypeOrTransport ] ) { + + options.dataTypes.unshift( dataTypeOrTransport ); + inspect( dataTypeOrTransport ); + return false; + } else if ( seekingTransport ) { + return !( selected = dataTypeOrTransport ); + } + } ); + return selected; + } + + return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" ); +} + +// A special extend for ajax options +// that takes "flat" options (not to be deep extended) +// Fixes #9887 +function ajaxExtend( target, src ) { + var key, deep, + flatOptions = jQuery.ajaxSettings.flatOptions || {}; + + for ( key in src ) { + if ( src[ key ] !== undefined ) { + ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; + } + } + if ( deep ) { + jQuery.extend( true, target, deep ); + } + + return target; +} + +/* Handles responses to an ajax request: + * - finds the right dataType (mediates between content-type and expected dataType) + * - returns the corresponding response + */ +function ajaxHandleResponses( s, jqXHR, responses ) { + + var ct, type, finalDataType, firstDataType, + contents = s.contents, + dataTypes = s.dataTypes; + + // Remove auto dataType and get content-type in the process + while ( dataTypes[ 0 ] === "*" ) { + dataTypes.shift(); + if ( ct === undefined ) { + ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" ); + } + } + + // Check if we're dealing with a known content-type + if ( ct ) { + for ( type in contents ) { + if ( contents[ type ] && contents[ type ].test( ct ) ) { + dataTypes.unshift( type ); + break; + } + } + } + + // Check to see if we have a response for the expected dataType + if ( dataTypes[ 0 ] in responses ) { + finalDataType = dataTypes[ 0 ]; + } else { + + // Try convertible dataTypes + for ( type in responses ) { + if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) { + finalDataType = type; + break; + } + if ( !firstDataType ) { + firstDataType = type; + } + } + + // Or just use first one + finalDataType = finalDataType || firstDataType; + } + + // If we found a dataType + // We add the dataType to the list if needed + // and return the corresponding response + if ( finalDataType ) { + if ( finalDataType !== dataTypes[ 0 ] ) { + dataTypes.unshift( finalDataType ); + } + return responses[ finalDataType ]; + } +} + +/* Chain conversions given the request and the original response + * Also sets the responseXXX fields on the jqXHR instance + */ +function ajaxConvert( s, response, jqXHR, isSuccess ) { + var conv2, current, conv, tmp, prev, + converters = {}, + + // Work with a copy of dataTypes in case we need to modify it for conversion + dataTypes = s.dataTypes.slice(); + + // Create converters map with lowercased keys + if ( dataTypes[ 1 ] ) { + for ( conv in s.converters ) { + converters[ conv.toLowerCase() ] = s.converters[ conv ]; + } + } + + current = dataTypes.shift(); + + // Convert to each sequential dataType + while ( current ) { + + if ( s.responseFields[ current ] ) { + jqXHR[ s.responseFields[ current ] ] = response; + } + + // Apply the dataFilter if provided + if ( !prev && isSuccess && s.dataFilter ) { + response = s.dataFilter( response, s.dataType ); + } + + prev = current; + current = dataTypes.shift(); + + if ( current ) { + + // There's only work to do if current dataType is non-auto + if ( current === "*" ) { + + current = prev; + + // Convert response if prev dataType is non-auto and differs from current + } else if ( prev !== "*" && prev !== current ) { + + // Seek a direct converter + conv = converters[ prev + " " + current ] || converters[ "* " + current ]; + + // If none found, seek a pair + if ( !conv ) { + for ( conv2 in converters ) { + + // If conv2 outputs current + tmp = conv2.split( " " ); + if ( tmp[ 1 ] === current ) { + + // If prev can be converted to accepted input + conv = converters[ prev + " " + tmp[ 0 ] ] || + converters[ "* " + tmp[ 0 ] ]; + if ( conv ) { + + // Condense equivalence converters + if ( conv === true ) { + conv = converters[ conv2 ]; + + // Otherwise, insert the intermediate dataType + } else if ( converters[ conv2 ] !== true ) { + current = tmp[ 0 ]; + dataTypes.unshift( tmp[ 1 ] ); + } + break; + } + } + } + } + + // Apply converter (if not an equivalence) + if ( conv !== true ) { + + // Unless errors are allowed to bubble, catch and return them + if ( conv && s.throws ) { + response = conv( response ); + } else { + try { + response = conv( response ); + } catch ( e ) { + return { + state: "parsererror", + error: conv ? e : "No conversion from " + prev + " to " + current + }; + } + } + } + } + } + } + + return { state: "success", data: response }; +} + +jQuery.extend( { + + // Counter for holding the number of active queries + active: 0, + + // Last-Modified header cache for next request + lastModified: {}, + etag: {}, + + ajaxSettings: { + url: location.href, + type: "GET", + isLocal: rlocalProtocol.test( location.protocol ), + global: true, + processData: true, + async: true, + contentType: "application/x-www-form-urlencoded; charset=UTF-8", + + /* + timeout: 0, + data: null, + dataType: null, + username: null, + password: null, + cache: null, + throws: false, + traditional: false, + headers: {}, + */ + + accepts: { + "*": allTypes, + text: "text/plain", + html: "text/html", + xml: "application/xml, text/xml", + json: "application/json, text/javascript" + }, + + contents: { + xml: /\bxml\b/, + html: /\bhtml/, + json: /\bjson\b/ + }, + + responseFields: { + xml: "responseXML", + text: "responseText", + json: "responseJSON" + }, + + // Data converters + // Keys separate source (or catchall "*") and destination types with a single space + converters: { + + // Convert anything to text + "* text": String, + + // Text to html (true = no transformation) + "text html": true, + + // Evaluate text as a json expression + "text json": JSON.parse, + + // Parse text as xml + "text xml": jQuery.parseXML + }, + + // For options that shouldn't be deep extended: + // you can add your own custom options here if + // and when you create one that shouldn't be + // deep extended (see ajaxExtend) + flatOptions: { + url: true, + context: true + } + }, + + // Creates a full fledged settings object into target + // with both ajaxSettings and settings fields. + // If target is omitted, writes into ajaxSettings. + ajaxSetup: function( target, settings ) { + return settings ? + + // Building a settings object + ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) : + + // Extending ajaxSettings + ajaxExtend( jQuery.ajaxSettings, target ); + }, + + ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), + ajaxTransport: addToPrefiltersOrTransports( transports ), + + // Main method + ajax: function( url, options ) { + + // If url is an object, simulate pre-1.5 signature + if ( typeof url === "object" ) { + options = url; + url = undefined; + } + + // Force options to be an object + options = options || {}; + + var transport, + + // URL without anti-cache param + cacheURL, + + // Response headers + responseHeadersString, + responseHeaders, + + // timeout handle + timeoutTimer, + + // Url cleanup var + urlAnchor, + + // Request state (becomes false upon send and true upon completion) + completed, + + // To know if global events are to be dispatched + fireGlobals, + + // Loop variable + i, + + // uncached part of the url + uncached, + + // Create the final options object + s = jQuery.ajaxSetup( {}, options ), + + // Callbacks context + callbackContext = s.context || s, + + // Context for global events is callbackContext if it is a DOM node or jQuery collection + globalEventContext = s.context && + ( callbackContext.nodeType || callbackContext.jquery ) ? + jQuery( callbackContext ) : + jQuery.event, + + // Deferreds + deferred = jQuery.Deferred(), + completeDeferred = jQuery.Callbacks( "once memory" ), + + // Status-dependent callbacks + statusCode = s.statusCode || {}, + + // Headers (they are sent all at once) + requestHeaders = {}, + requestHeadersNames = {}, + + // Default abort message + strAbort = "canceled", + + // Fake xhr + jqXHR = { + readyState: 0, + + // Builds headers hashtable if needed + getResponseHeader: function( key ) { + var match; + if ( completed ) { + if ( !responseHeaders ) { + responseHeaders = {}; + while ( ( match = rheaders.exec( responseHeadersString ) ) ) { + responseHeaders[ match[ 1 ].toLowerCase() + " " ] = + ( responseHeaders[ match[ 1 ].toLowerCase() + " " ] || [] ) + .concat( match[ 2 ] ); + } + } + match = responseHeaders[ key.toLowerCase() + " " ]; + } + return match == null ? null : match.join( ", " ); + }, + + // Raw string + getAllResponseHeaders: function() { + return completed ? responseHeadersString : null; + }, + + // Caches the header + setRequestHeader: function( name, value ) { + if ( completed == null ) { + name = requestHeadersNames[ name.toLowerCase() ] = + requestHeadersNames[ name.toLowerCase() ] || name; + requestHeaders[ name ] = value; + } + return this; + }, + + // Overrides response content-type header + overrideMimeType: function( type ) { + if ( completed == null ) { + s.mimeType = type; + } + return this; + }, + + // Status-dependent callbacks + statusCode: function( map ) { + var code; + if ( map ) { + if ( completed ) { + + // Execute the appropriate callbacks + jqXHR.always( map[ jqXHR.status ] ); + } else { + + // Lazy-add the new callbacks in a way that preserves old ones + for ( code in map ) { + statusCode[ code ] = [ statusCode[ code ], map[ code ] ]; + } + } + } + return this; + }, + + // Cancel the request + abort: function( statusText ) { + var finalText = statusText || strAbort; + if ( transport ) { + transport.abort( finalText ); + } + done( 0, finalText ); + return this; + } + }; + + // Attach deferreds + deferred.promise( jqXHR ); + + // Add protocol if not provided (prefilters might expect it) + // Handle falsy url in the settings object (#10093: consistency with old signature) + // We also use the url parameter if available + s.url = ( ( url || s.url || location.href ) + "" ) + .replace( rprotocol, location.protocol + "//" ); + + // Alias method option to type as per ticket #12004 + s.type = options.method || options.type || s.method || s.type; + + // Extract dataTypes list + s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ]; + + // A cross-domain request is in order when the origin doesn't match the current origin. + if ( s.crossDomain == null ) { + urlAnchor = document.createElement( "a" ); + + // Support: IE <=8 - 11, Edge 12 - 15 + // IE throws exception on accessing the href property if url is malformed, + // e.g. http://example.com:80x/ + try { + urlAnchor.href = s.url; + + // Support: IE <=8 - 11 only + // Anchor's host property isn't correctly set when s.url is relative + urlAnchor.href = urlAnchor.href; + s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== + urlAnchor.protocol + "//" + urlAnchor.host; + } catch ( e ) { + + // If there is an error parsing the URL, assume it is crossDomain, + // it can be rejected by the transport if it is invalid + s.crossDomain = true; + } + } + + // Convert data if not already a string + if ( s.data && s.processData && typeof s.data !== "string" ) { + s.data = jQuery.param( s.data, s.traditional ); + } + + // Apply prefilters + inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); + + // If request was aborted inside a prefilter, stop there + if ( completed ) { + return jqXHR; + } + + // We can fire global events as of now if asked to + // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118) + fireGlobals = jQuery.event && s.global; + + // Watch for a new set of requests + if ( fireGlobals && jQuery.active++ === 0 ) { + jQuery.event.trigger( "ajaxStart" ); + } + + // Uppercase the type + s.type = s.type.toUpperCase(); + + // Determine if request has content + s.hasContent = !rnoContent.test( s.type ); + + // Save the URL in case we're toying with the If-Modified-Since + // and/or If-None-Match header later on + // Remove hash to simplify url manipulation + cacheURL = s.url.replace( rhash, "" ); + + // More options handling for requests with no content + if ( !s.hasContent ) { + + // Remember the hash so we can put it back + uncached = s.url.slice( cacheURL.length ); + + // If data is available and should be processed, append data to url + if ( s.data && ( s.processData || typeof s.data === "string" ) ) { + cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data; + + // #9682: remove data so that it's not used in an eventual retry + delete s.data; + } + + // Add or update anti-cache param if needed + if ( s.cache === false ) { + cacheURL = cacheURL.replace( rantiCache, "$1" ); + uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce.guid++ ) + + uncached; + } + + // Put hash and anti-cache on the URL that will be requested (gh-1732) + s.url = cacheURL + uncached; + + // Change '%20' to '+' if this is encoded form body content (gh-2658) + } else if ( s.data && s.processData && + ( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) { + s.data = s.data.replace( r20, "+" ); + } + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + if ( jQuery.lastModified[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] ); + } + if ( jQuery.etag[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] ); + } + } + + // Set the correct header, if data is being sent + if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { + jqXHR.setRequestHeader( "Content-Type", s.contentType ); + } + + // Set the Accepts header for the server, depending on the dataType + jqXHR.setRequestHeader( + "Accept", + s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ? + s.accepts[ s.dataTypes[ 0 ] ] + + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : + s.accepts[ "*" ] + ); + + // Check for headers option + for ( i in s.headers ) { + jqXHR.setRequestHeader( i, s.headers[ i ] ); + } + + // Allow custom headers/mimetypes and early abort + if ( s.beforeSend && + ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) { + + // Abort if not done already and return + return jqXHR.abort(); + } + + // Aborting is no longer a cancellation + strAbort = "abort"; + + // Install callbacks on deferreds + completeDeferred.add( s.complete ); + jqXHR.done( s.success ); + jqXHR.fail( s.error ); + + // Get transport + transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); + + // If no transport, we auto-abort + if ( !transport ) { + done( -1, "No Transport" ); + } else { + jqXHR.readyState = 1; + + // Send global event + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); + } + + // If request was aborted inside ajaxSend, stop there + if ( completed ) { + return jqXHR; + } + + // Timeout + if ( s.async && s.timeout > 0 ) { + timeoutTimer = window.setTimeout( function() { + jqXHR.abort( "timeout" ); + }, s.timeout ); + } + + try { + completed = false; + transport.send( requestHeaders, done ); + } catch ( e ) { + + // Rethrow post-completion exceptions + if ( completed ) { + throw e; + } + + // Propagate others as results + done( -1, e ); + } + } + + // Callback for when everything is done + function done( status, nativeStatusText, responses, headers ) { + var isSuccess, success, error, response, modified, + statusText = nativeStatusText; + + // Ignore repeat invocations + if ( completed ) { + return; + } + + completed = true; + + // Clear timeout if it exists + if ( timeoutTimer ) { + window.clearTimeout( timeoutTimer ); + } + + // Dereference transport for early garbage collection + // (no matter how long the jqXHR object will be used) + transport = undefined; + + // Cache response headers + responseHeadersString = headers || ""; + + // Set readyState + jqXHR.readyState = status > 0 ? 4 : 0; + + // Determine if successful + isSuccess = status >= 200 && status < 300 || status === 304; + + // Get response data + if ( responses ) { + response = ajaxHandleResponses( s, jqXHR, responses ); + } + + // Use a noop converter for missing script but not if jsonp + if ( !isSuccess && + jQuery.inArray( "script", s.dataTypes ) > -1 && + jQuery.inArray( "json", s.dataTypes ) < 0 ) { + s.converters[ "text script" ] = function() {}; + } + + // Convert no matter what (that way responseXXX fields are always set) + response = ajaxConvert( s, response, jqXHR, isSuccess ); + + // If successful, handle type chaining + if ( isSuccess ) { + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + modified = jqXHR.getResponseHeader( "Last-Modified" ); + if ( modified ) { + jQuery.lastModified[ cacheURL ] = modified; + } + modified = jqXHR.getResponseHeader( "etag" ); + if ( modified ) { + jQuery.etag[ cacheURL ] = modified; + } + } + + // if no content + if ( status === 204 || s.type === "HEAD" ) { + statusText = "nocontent"; + + // if not modified + } else if ( status === 304 ) { + statusText = "notmodified"; + + // If we have data, let's convert it + } else { + statusText = response.state; + success = response.data; + error = response.error; + isSuccess = !error; + } + } else { + + // Extract error from statusText and normalize for non-aborts + error = statusText; + if ( status || !statusText ) { + statusText = "error"; + if ( status < 0 ) { + status = 0; + } + } + } + + // Set data for the fake xhr object + jqXHR.status = status; + jqXHR.statusText = ( nativeStatusText || statusText ) + ""; + + // Success/Error + if ( isSuccess ) { + deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); + } else { + deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); + } + + // Status-dependent callbacks + jqXHR.statusCode( statusCode ); + statusCode = undefined; + + if ( fireGlobals ) { + globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError", + [ jqXHR, s, isSuccess ? success : error ] ); + } + + // Complete + completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); + + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); + + // Handle the global AJAX counter + if ( !( --jQuery.active ) ) { + jQuery.event.trigger( "ajaxStop" ); + } + } + } + + return jqXHR; + }, + + getJSON: function( url, data, callback ) { + return jQuery.get( url, data, callback, "json" ); + }, + + getScript: function( url, callback ) { + return jQuery.get( url, undefined, callback, "script" ); + } +} ); + +jQuery.each( [ "get", "post" ], function( _i, method ) { + jQuery[ method ] = function( url, data, callback, type ) { + + // Shift arguments if data argument was omitted + if ( isFunction( data ) ) { + type = type || callback; + callback = data; + data = undefined; + } + + // The url can be an options object (which then must have .url) + return jQuery.ajax( jQuery.extend( { + url: url, + type: method, + dataType: type, + data: data, + success: callback + }, jQuery.isPlainObject( url ) && url ) ); + }; +} ); + +jQuery.ajaxPrefilter( function( s ) { + var i; + for ( i in s.headers ) { + if ( i.toLowerCase() === "content-type" ) { + s.contentType = s.headers[ i ] || ""; + } + } +} ); + + +jQuery._evalUrl = function( url, options, doc ) { + return jQuery.ajax( { + url: url, + + // Make this explicit, since user can override this through ajaxSetup (#11264) + type: "GET", + dataType: "script", + cache: true, + async: false, + global: false, + + // Only evaluate the response if it is successful (gh-4126) + // dataFilter is not invoked for failure responses, so using it instead + // of the default converter is kludgy but it works. + converters: { + "text script": function() {} + }, + dataFilter: function( response ) { + jQuery.globalEval( response, options, doc ); + } + } ); +}; + + +jQuery.fn.extend( { + wrapAll: function( html ) { + var wrap; + + if ( this[ 0 ] ) { + if ( isFunction( html ) ) { + html = html.call( this[ 0 ] ); + } + + // The elements to wrap the target around + wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true ); + + if ( this[ 0 ].parentNode ) { + wrap.insertBefore( this[ 0 ] ); + } + + wrap.map( function() { + var elem = this; + + while ( elem.firstElementChild ) { + elem = elem.firstElementChild; + } + + return elem; + } ).append( this ); + } + + return this; + }, + + wrapInner: function( html ) { + if ( isFunction( html ) ) { + return this.each( function( i ) { + jQuery( this ).wrapInner( html.call( this, i ) ); + } ); + } + + return this.each( function() { + var self = jQuery( this ), + contents = self.contents(); + + if ( contents.length ) { + contents.wrapAll( html ); + + } else { + self.append( html ); + } + } ); + }, + + wrap: function( html ) { + var htmlIsFunction = isFunction( html ); + + return this.each( function( i ) { + jQuery( this ).wrapAll( htmlIsFunction ? html.call( this, i ) : html ); + } ); + }, + + unwrap: function( selector ) { + this.parent( selector ).not( "body" ).each( function() { + jQuery( this ).replaceWith( this.childNodes ); + } ); + return this; + } +} ); + + +jQuery.expr.pseudos.hidden = function( elem ) { + return !jQuery.expr.pseudos.visible( elem ); +}; +jQuery.expr.pseudos.visible = function( elem ) { + return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ); +}; + + + + +jQuery.ajaxSettings.xhr = function() { + try { + return new window.XMLHttpRequest(); + } catch ( e ) {} +}; + +var xhrSuccessStatus = { + + // File protocol always yields status code 0, assume 200 + 0: 200, + + // Support: IE <=9 only + // #1450: sometimes IE returns 1223 when it should be 204 + 1223: 204 + }, + xhrSupported = jQuery.ajaxSettings.xhr(); + +support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported ); +support.ajax = xhrSupported = !!xhrSupported; + +jQuery.ajaxTransport( function( options ) { + var callback, errorCallback; + + // Cross domain only allowed if supported through XMLHttpRequest + if ( support.cors || xhrSupported && !options.crossDomain ) { + return { + send: function( headers, complete ) { + var i, + xhr = options.xhr(); + + xhr.open( + options.type, + options.url, + options.async, + options.username, + options.password + ); + + // Apply custom fields if provided + if ( options.xhrFields ) { + for ( i in options.xhrFields ) { + xhr[ i ] = options.xhrFields[ i ]; + } + } + + // Override mime type if needed + if ( options.mimeType && xhr.overrideMimeType ) { + xhr.overrideMimeType( options.mimeType ); + } + + // X-Requested-With header + // For cross-domain requests, seeing as conditions for a preflight are + // akin to a jigsaw puzzle, we simply never set it to be sure. + // (it can always be set on a per-request basis or even using ajaxSetup) + // For same-domain requests, won't change header if already provided. + if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) { + headers[ "X-Requested-With" ] = "XMLHttpRequest"; + } + + // Set headers + for ( i in headers ) { + xhr.setRequestHeader( i, headers[ i ] ); + } + + // Callback + callback = function( type ) { + return function() { + if ( callback ) { + callback = errorCallback = xhr.onload = + xhr.onerror = xhr.onabort = xhr.ontimeout = + xhr.onreadystatechange = null; + + if ( type === "abort" ) { + xhr.abort(); + } else if ( type === "error" ) { + + // Support: IE <=9 only + // On a manual native abort, IE9 throws + // errors on any property access that is not readyState + if ( typeof xhr.status !== "number" ) { + complete( 0, "error" ); + } else { + complete( + + // File: protocol always yields status 0; see #8605, #14207 + xhr.status, + xhr.statusText + ); + } + } else { + complete( + xhrSuccessStatus[ xhr.status ] || xhr.status, + xhr.statusText, + + // Support: IE <=9 only + // IE9 has no XHR2 but throws on binary (trac-11426) + // For XHR2 non-text, let the caller handle it (gh-2498) + ( xhr.responseType || "text" ) !== "text" || + typeof xhr.responseText !== "string" ? + { binary: xhr.response } : + { text: xhr.responseText }, + xhr.getAllResponseHeaders() + ); + } + } + }; + }; + + // Listen to events + xhr.onload = callback(); + errorCallback = xhr.onerror = xhr.ontimeout = callback( "error" ); + + // Support: IE 9 only + // Use onreadystatechange to replace onabort + // to handle uncaught aborts + if ( xhr.onabort !== undefined ) { + xhr.onabort = errorCallback; + } else { + xhr.onreadystatechange = function() { + + // Check readyState before timeout as it changes + if ( xhr.readyState === 4 ) { + + // Allow onerror to be called first, + // but that will not handle a native abort + // Also, save errorCallback to a variable + // as xhr.onerror cannot be accessed + window.setTimeout( function() { + if ( callback ) { + errorCallback(); + } + } ); + } + }; + } + + // Create the abort callback + callback = callback( "abort" ); + + try { + + // Do send the request (this may raise an exception) + xhr.send( options.hasContent && options.data || null ); + } catch ( e ) { + + // #14683: Only rethrow if this hasn't been notified as an error yet + if ( callback ) { + throw e; + } + } + }, + + abort: function() { + if ( callback ) { + callback(); + } + } + }; + } +} ); + + + + +// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432) +jQuery.ajaxPrefilter( function( s ) { + if ( s.crossDomain ) { + s.contents.script = false; + } +} ); + +// Install script dataType +jQuery.ajaxSetup( { + accepts: { + script: "text/javascript, application/javascript, " + + "application/ecmascript, application/x-ecmascript" + }, + contents: { + script: /\b(?:java|ecma)script\b/ + }, + converters: { + "text script": function( text ) { + jQuery.globalEval( text ); + return text; + } + } +} ); + +// Handle cache's special case and crossDomain +jQuery.ajaxPrefilter( "script", function( s ) { + if ( s.cache === undefined ) { + s.cache = false; + } + if ( s.crossDomain ) { + s.type = "GET"; + } +} ); + +// Bind script tag hack transport +jQuery.ajaxTransport( "script", function( s ) { + + // This transport only deals with cross domain or forced-by-attrs requests + if ( s.crossDomain || s.scriptAttrs ) { + var script, callback; + return { + send: function( _, complete ) { + script = jQuery( " + +{% endmacro %} \ No newline at end of file diff --git a/_static/wordmark.png b/_static/wordmark.png new file mode 100644 index 0000000..2e11bae Binary files /dev/null and b/_static/wordmark.png differ diff --git a/_static/wordmark.svg b/_static/wordmark.svg new file mode 100644 index 0000000..72aa762 --- /dev/null +++ b/_static/wordmark.svg @@ -0,0 +1,230 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Param + + diff --git a/about.html b/about.html new file mode 100644 index 0000000..b7b171a --- /dev/null +++ b/about.html @@ -0,0 +1,684 @@ + + + + + + + + + + + + About — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

About#

+

Param is completely open source, available under a BSD license, freely for both commercial and non-commercial use. Param was originally developed at the University of Texas at Austin and the University of Edinburgh with funding from the US National Institutes of Health grant 1R01-MH66991. Param is now maintained by Anaconda Inc. and by community contributors.

+

Param is maintained as part of the HoloViz family of tools. The holoviz.org website shows how to use Param together with other libraries to solve complex problems, with detailed tutorials and examples. Each of the HoloViz tools builds on Param, as do many of the example projects at examples.holoviz.org.

+

If you have any questions or usage issues visit the Param Discourse forum, and if you want to report bugs or request new features, first see if it’s already in our list of open issues and then add to the issue or open a new one if needed.

+

If you like Param and have built something you want to share, tweet a link or screenshot of your latest creation at @HoloViz_org. Thanks!

+
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/comparisons.html b/comparisons.html new file mode 100644 index 0000000..df53359 --- /dev/null +++ b/comparisons.html @@ -0,0 +1,794 @@ + + + + + + + + + + + + Comparison to other approaches — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

Comparison to other approaches#

+

Param was first developed in 2003 for Python 2.1 as part of a long-running brain simulation project, and was made into a separate package on Github in 2012. In the interim a variety of other libraries solving some of the same problems have been developed, including:

+ +

Plus, Python itself has incorporated mechanisms addressing some of the same issues:

+ +

Each of these approaches overlaps with some but by no means all of the functionality provided by Param, as described below. Also see the comparisons provided with attrs and by an attr user, which were written about attrs but also apply just as well to Param (with Param differing in also providing e.g. GUI support as listed below). Other info comparing attrs to pydantic is also available.

+

Here we will use the word “parameter” as a generic term for a Python attribute, a Param Parameter, a Traitlets/HasTraits trait, or an attr attr.ib.

+
+

Brevity of code#

+

Python properties can be used to express nearly anything Param or Traitlets can do, but they require at least an order of magnitude more code to do it. You can think of Param and Traitlets as a pre-written implementation of a Python property that implements a configurable parameter. Avoiding having to write that code each time is a big win, because configurable parameters are all over any Python codebase, and Parameter/attr.ib/pydantic/Traits-based approaches lead to much simpler and more maintainable codebases.

+

Specifically, where Param or Traitlets can express an automatically validated type and bounds on an attribute in a simple and localized one-line declaration like a = param.Integer(5, bounds=(1,10)), implementing the same functionality using properties requires changes to the constructor plus separate explicit get and set methods, each with at least a half-dozen lines of validation code. Though this get/set/validate code may seem easy to write, it is difficult to read, difficult to maintain, and difficult to make comprehensive or exhaustive. +In practice, most programmers simply skip validation or implement it only partially, leaving their code behaving in undefined ways for unexpected inputs. With Param or Traitlets, you don’t have to choose between short/readable/maintainable code and heavily validated code; you can have both for far less work!

+

pydantic and attrs provide many of these same benefits, though attrs type and bounds validation is treated as an extra step that is more general but also typically much more verbose.

+
+
+

Runtime checking#

+

Python 3 type annotations allow users to specify types for attributes and function returns, but these types are not normally checked at runtime, and so they do not have the same role of validating user input or programmer error as the type declarations in Params, Traits, Traitlets, pydantic, and attr. They also are limited to the type, so they cannot enforce constraints on range (‘state’ must be in the list [‘Alabama’, ‘Alaska’,…]). Thus even if type hinting is used, programmers still need to write code to actually validate the inputs to functions and methods, which is the role of packages like Param and Traitlets. Note that Pydantic focuses on generating valid outputs at runtime rather than detecting invalid inputs, so it may or may not be suitable for the same types of applications as the other libraries discussed here.

+
+
+

Generality and ease of integration with your project#

+

The various Python features listed above are part of the standard library with the versions indicated above, and so do not add any dependencies at all to your build process, as long as you restrict yourself to the Python versions where that support was added.

+

Param, Traitlets, Pydantic, and attrs are all pure Python projects, with minimal dependencies, and so adding them to any project is generally straightforward. They also support a wide range of Python versions, making them usable in cases where the more recent Python-language features are not available.

+

Django models offer some of the same ways to declare parameters and generate web-based GUIs (below), but require the extensive Django web framework and normally rely on a database and web server, which in practice limit their usage to users building dedicated web sites, unlike the no-dependency Param and attrs libraries that can be added to Python projects of any type.

+

Traits is a very heavyweight solution, requiring installation and C compilation of a large suite of tools, which makes it difficult to include in separate projects.

+
+
+

GUI toolkits#

+

Several of these packages support automatically mapping parameters/traits/attributes into GUI widgets. Although any of them could in principle be supported for any GUI toolkit, only certain GUI interfaces are currently available:

+
    +
  • Panel: Jupyter and Bokeh-server support for Param, mapping Parameters to widgets and ParameterizedObjects to sets of widgets

  • +
  • ParamTk: (unsupported) TKinter support for Param

  • +
  • IPywidgets: Jupyter support for Traitlets, but without automatic mapping from trait to widget

  • +
  • TraitsUI: wxWidgets and Qt support for Traits

  • +
+
+
+

Dynamic values#

+

Param, Traits, Traitlets, Pydantic, and attrs all allow any Python expression to be supplied for initializing parameters, allowing parameter default values to be computed at the time a module is first loaded. Pydantic, Traits, and Traitlets also allow a class author to add code for a given parameter to compute a default value on first access.

+
>>> from time import time, sleep
+>>> import traitlets as tr
+>>> class A(tr.HasTraits):
+...        instantiation_time = tr.Float()
+...        @tr.default('instantiation_time')
+...        def _look_up_time(self):
+...            return time()
+...
+>>> a=A()
+>>> time()
+1634594159.2040331
+>>> sleep(1)
+>>> time()
+1634594165.3485172
+>>> a.instantiation_time
+1634594167.812151
+>>> a.instantiation_time
+1634594167.812151
+>>> sleep(1)
+>>> b=A()
+>>> b.instantiation_time
+1634594178.427819
+
+
+

Param’s equivalent decorator @param.depends(on_init=True) will run a method when the Parameterized class is instantiated, not on first access. +On the other hand, Param does allow fully dynamic values for any access to a numeric Parameter instance, not just the original instantiation:

+
>>> from time import time
+>>> import param
+>>> class A(param.Parameterized):
+...     val=param.Number(0)
+...
+>>> a=A()
+>>> a.val
+0
+>>> a.val=lambda:time()
+>>> a.val
+1475587455.437027
+>>> a.val
+1475587456.501314
+
+
+
+
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/developer_guide.html b/developer_guide.html new file mode 100644 index 0000000..aadd260 --- /dev/null +++ b/developer_guide.html @@ -0,0 +1,733 @@ + + + + + + + + + + + + Developer guide — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

Developer guide#

+
+

Setup#

+

The source code for Param is hosted on GitHub. To clone the source repository, issue the following command:

+
git clone https://github.com/holoviz/param.git
+
+
+

This will create a param directory at your file system location.

+

Param relies on hatch to manage the project. Follow the instructions to install it. Once installed, run the following command to create the default environment and activate it, it contains the dependencies required to develop Param:

+
hatch shell
+
+
+
+
+

Testing#

+

The simplest way to run the unit tests is to run the following command:

+
hatch run tests
+
+
+

You can also run the examples tests, i.e. check that the notebooks run without any error, with:

+
hatch run examples
+
+
+
+
+

Documentation building#

+

Run the following command to build the documentation:

+
hatch run docs:build
+
+
+

Once completed, the built site can be found in the builtdocs folder.

+
+
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/genindex.html b/genindex.html new file mode 100644 index 0000000..8521dca --- /dev/null +++ b/genindex.html @@ -0,0 +1,1226 @@ + + + + + + + + + + + Index — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+ + + + + +
+ + +

Index

+ +
+ _ + | A + | B + | C + | D + | E + | F + | G + | H + | I + | J + | L + | M + | N + | O + | P + | R + | S + | T + | U + | V + | W + | X + +
+

_

+ + +
+ +

A

+ + + +
+ +

B

+ + + +
+ +

C

+ + + +
+ +

D

+ + + +
+ +

E

+ + + +
+ +

F

+ + + +
+ +

G

+ + + +
+ +

H

+ + +
+ +

I

+ + + +
+ +

J

+ + + +
+ +

L

+ + + +
+ +

M

+ + + +
+ +

N

+ + + +
+ +

O

+ + + +
+ +

P

+ + + +
+ +

R

+ + + +
+ +

S

+ + + +
+ +

T

+ + + +
+ +

U

+ + + +
+ +

V

+ + + +
+ +

W

+ + + +
+ +

X

+ + + +
+ + + +
+ + + +
+ +
+ +
+
+
+ +
+ +
+ +
+ + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/getting_started.html b/getting_started.html new file mode 100644 index 0000000..93e0313 --- /dev/null +++ b/getting_started.html @@ -0,0 +1,808 @@ + + + + + + + + + + + + Getting Started — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

Getting Started#

+
+

Installation#

+

Param has no required dependencies outside of Python’s standard library, and so it is very easy to install.

+

Official releases of Param are available from conda (defaults version conda-forge version) and PyPI (PyPI version), and can be installed via:

+
conda install param
+
+
+

or

+
pip install param
+
+
+
+
+

Using Param to get simple, robust code#

+

The param library gives you Parameters, which are used in Parameterized classes.

+

A Parameter is a special type of Python class attribute extended to have various optional features such as type and range checking, dynamically generated values, documentation strings, default values, etc., each of which is inherited from parent classes if not specified in a subclass or instance:

+
import param
+
+class A(param.Parameterized):
+    title = param.String(default="sum", doc="Title for the result")
+
+class B(A):
+    a = param.Integer(2, bounds=(0, 10), doc="First addend")
+    b = param.Integer(3, bounds=(0, 10), doc="Second addend")
+
+    def __call__(self):
+        return self.title + ": " + str(self.a + self.b)
+
+
+
>> o1 = B(b=4, title="Sum")
+>> o1.a = 5
+>> o1()
+'Sum: 9'
+
+
+
>> o1.b
+4
+
+
+

As you can see, the Parameters defined here work precisely like any other Python attributes in your code, so it’s generally quite straightforward to migrate an existing class to use Param. Just inherit from param.Parameterized, then provide an optional Parameter declaration for each parameter the object accepts, including ranges and allowed values if appropriate. You only need to declare and document each parameter once, at the highest superclass where it applies, and its default value all the other metadata will be inherited by each subclass.

+

Once you’ve declared your parameters, a whole wealth of features and better behavior is now unlocked! For instance, what happens if a user tries to supply some inappropriate data? With Param, such errors will be caught immediately:

+
>>> B(a="four")
+ValueError: Parameter 'a' must be an integer.
+
+>>> o2 = B()
+>>> o2.b = -5
+ValueError: Parameter 'b' must be at least 0
+
+
+

Of course, you could always add more code to an ordinary Python class to check for errors like that, but as described in the User Guide, that quickly gets unwieldy, with dozens of lines of exceptions, assertions, property definitions, and decorators that obscure what you actually wrote your code to do. Param lets you focus on the code you’re writing, while letting your users know exactly what inputs they can supply.

+

The types in Param may remind you of the static types found in some languages, but here the validation is done at runtime and is checking not just types but also numeric ranges or for specific allowed values. Param thus helps you not just with programming correctness, as for static types, but also for validating user inputs. Validating user inputs is generally a large fraction of a program’s code, because such inputs are a huge source of vulnerabilities and potential error conditions, and Param lets you avoid ever having to write nearly any of that code.

+

The User Guide explains all the other Param features for simplifying your codebase, improving input validation, allowing flexible configuration, and supporting serialization.

+
+
+

Using Param for configuration#

+

Once you have declared your Parameters, they are now fully accessible from Python in a way that helps users of your code configure it and control it if they wish. Without any extra work by the author of the class, a user can use Python to reconfigure any of the defaults that will be used when they use these objects:

+
>>> A.title = "The sum is"
+>>> B.a = 6
+
+>>> o3 = B()
+>>> o3()
+'The sum is: 9'
+
+
+

Because this configuration is all declarative, the underlying values can come from a YAML file, a JSON blob, URL parameters, CLI arguments, or just about any source, letting you provide users full control over configuration with very little effort. Once you write a Parameterized class, it’s up to a user to choose how they want to work with it; your job is done!

+
+
+

Using Param to explore parameter spaces#

+

Param is valuable for any Python codebase, but it offers features that are particularly well suited for running models, simulations, machine learning pipelines, or other programs where the same code needs to be evaluated multiple times to see how it behaves with different parameter values. To facilitate such usage, numeric parameters in Param can be set to a callable value, which will be evaluated every time the parameter is accessed:

+
>>> import random
+>>> o2 = B(a=lambda: random.randint(0,5))
+
+>>> o2(), o2(), o2(), o2()
+('The sum is: 6', 'The sum is: 7', 'The sum is: 3', 'The sum is: 3')
+
+
+

The code for B doesn’t have to have any special knowledge or processing of dynamic values, because accessing a always simply returns an integer, not the callable function:

+
>>> o2.a
+4
+
+
+

Thus the author of a Parameterized class does not have to take such dynamic values into account; their code simply works with whatever value is returned by the attribute lookup, whether it’s dynamic or not. This approach makes Parameterized code immediately ready for exploration across parameter values, whether or not the code’s author specifically provided for such usage.

+

Param includes a separate and optional module numbergen that makes it simple to generate streams of numeric values for use as Parameter values. numbergen objects are picklable (unlike a lambda as above) and can be combined into expressions to build up parameter sweeps or Monte Carlo simulations:

+
>>> import numbergen as ng
+
+>>> o3 = B(a=ng.Choice(choices= [2, 4, 6]),
+>>>       b = 1 + 2 * ng.UniformRandomInt(ubound=3))
+
+>>> o3(), o3(), o3(), o3()
+('The sum is: 11', 'The sum is: 3', 'The sum is: 13', 'The sum is: 7')
+
+
+

Numbergen objects support the usual arithmetic operations like +, -, *, /, //, %, **, and abs(), and so they can be freely combined with each other or with mathematical constants. They also optionally respect a global “time” (e.g. a simulation time or a logical counter), which lets you synchronize changes to dynamic values without any special coordination code.

+
+
+

Using Param to build GUIs#

+

Param is useful for any sort of programming, but if you need a GUI with widgets, it turns out that the information captured by a Parameter is very often already what is needed to build such a GUI. For instance, we can use the separate Panel library to create widgets in a web browser and display the output from the above class automatically.

+

Panel and other GUI libraries can of course explicitly instantiate widgets, so why use Param in this way? Simply put, this approach lets you cleanly separate your domain-specific code, clearly declaring the parameters it requires and respects, from your GUI code. The GUI code controls GUI issues like layout and font size, but the fundamental declaration of what parameters are available is done at the level of the code that actually uses it (classes A and B in this case). With Param, you can separately declare all your Parameters right where they are used, achieving robustness, type checking, and clear documentation, while avoiding having your GUI code be tightly bound up with your domain-specific details. This approach helps you build maintainable, general-purpose codebases that can easily be used with or without GUI interfaces, with unattended batch operation not needing any GUI support and GUIs not needing to be updated every time someone adds a new option or parameter to the underlying code.

+
+
+

Learning more#

+

The User Guide goes through the major features of Param and how to use them. If you are interested in GUI programming, also see the Param How-to guides in Panel, and the rest of the Panel docs. Have fun making your life better with Param!

+
+
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..9a84af8 --- /dev/null +++ b/index.html @@ -0,0 +1,667 @@ + + + + + + + + + + + + Welcome to Param! — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+ + + + + +
+ +
+

Welcome to Param!#

+

+

Are you a Python programmer? If so, you need Param, and check out our 5-minute intro video to see why!

+ +

Param is a library for handling all the user-modifiable parameters, arguments, and attributes that control your code. It provides automatic, robust error-checking while dramatically reducing boilerplate code, letting you focus on what you want your code to do rather than on checking for all the possible ways users could supply inappropriate values to a function or class.

+

Param lets you program declaratively in Python, stating facts about each of your parameters up front. Once you have done that, Param can handle the rest (type checking, range validation, documentation, serialization, and more!).

+

Param-based programs tend to contain much less code than other Python programs, instead just having easily readable and maintainable manifests of Parameters for each object or function. This way your remaining code can be much simpler and clearer, while users can also easily see how to use it properly. Plus, Param doesn’t require any code outside of the Python standard library, making it simple to add to any project.

+

Param is also useful as a way to keep your domain-specific code independent of any GUI or other user-interface code, letting you maintain a single codebase to support both GUI and non-GUI usage, with the GUI maintainable by UI experts and the domain-specific code maintained by domain experts.

+

To quickly see how Param works and can be used, jump straight into the Getting Started Guide, then check out the full functionality in the User Guide.

+
+
+
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/objects.inv b/objects.inv new file mode 100644 index 0000000..695f2f9 Binary files /dev/null and b/objects.inv differ diff --git a/py-modindex.html b/py-modindex.html new file mode 100644 index 0000000..6ff01b6 --- /dev/null +++ b/py-modindex.html @@ -0,0 +1,659 @@ + + + + + + + + + + + Python Module Index — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+ + + + + +
+ + +

Python Module Index

+ +
+ n | + p +
+ + + + + + + + + + + + + + + +
 
+ n
+ numbergen +
 
+ p
+ param +
    + param.serializer +
+ + +
+ + + +
+ +
+ +
+
+
+ +
+ +
+ +
+ + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/index.html b/reference/index.html new file mode 100644 index 0000000..3ef9433 --- /dev/null +++ b/reference/index.html @@ -0,0 +1,725 @@ + + + + + + + + + + + + API reference — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

API reference#

+

Param effectively installs two packages param and numbergen importable +under the same names. This section documents their public API.

+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/numbergen.html b/reference/numbergen.html new file mode 100644 index 0000000..a697a5c --- /dev/null +++ b/reference/numbergen.html @@ -0,0 +1,1050 @@ + + + + + + + + + + + + Numbergen API reference — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

Numbergen API reference#

+

Callable objects that generate numbers according to different distributions.

+
+
+class numbergen.BinaryOperator(lhs, rhs, operator, reverse=False, **args)[source]#
+

Bases: NumberGenerator

+

Applies any binary operator to NumberGenerators or numbers to yield a NumberGenerator.

+
+ +
+
+class numbergen.BoundedNumber(*, bounds, generator, name)[source]#
+

Bases: NumberGenerator

+

Function object that silently enforces numeric bounds on values +returned by a callable object.

+
+
generator = param.Callable(allow_None=True, allow_refs=False, label=’Generator’, nested_refs=False, rx=<param.reactive.reactive_ops object at 0x7f89343921f0>)

Object to call to generate values.

+
+
bounds = param.Parameter(allow_refs=False, default=(None, None), label=’Bounds’, nested_refs=False, rx=<param.reactive.reactive_ops object at 0x7f8934392c10>)

Legal range for the value returned, as a pair. + + The default bounds are (None,None), meaning there are actually + no bounds. One or both bounds can be set by specifying a + value. For instance, bounds=(None,10) means there is no lower + bound, and an upper bound of 10.

+
+
+
+ +
+
+class numbergen.BoxCar(*, duration, onset, time_dependent, time_fn, name)[source]#
+

Bases: NumberGenerator, TimeDependent

+

The boxcar function over the specified time interval. The bounds +are exclusive: zero is returned at the onset time and at the +offset (onset+duration).

+

If duration is None, then this reduces to a step function around the +onset value with no offset.

+

See http://en.wikipedia.org/wiki/Boxcar_function

+

Parameters inherited from:

+
+

numbergen.TimeAware: time_fn

+

numbergen.TimeDependent: time_dependent

+
+
+
onset = param.Number(allow_refs=False, default=0.0, inclusive_bounds=(True, True), label=’Onset’, nested_refs=False, rx=<param.reactive.reactive_ops object at 0x7f8934554610>)

Time of onset.

+
+
duration = param.Number(allow_None=True, allow_refs=False, bounds=(0.0, None), inclusive_bounds=(True, True), label=’Duration’, nested_refs=False, rx=<param.reactive.reactive_ops object at 0x7f8934554460>)

Duration of step value.

+
+
+
+ +
+
+class numbergen.Choice(*, choices, seed, random_generator, time_dependent, time_fn, name)[source]#
+

Bases: RandomDistribution

+

Return a random element from the specified list of choices.

+

Accepts items of any type, though they are typically numbers. +See the choice() function in the random module for further details.

+

Parameters inherited from:

+
+

numbergen.TimeAware: time_dependent, time_fn

+

numbergen.TimeAwareRandomState: random_generator

+

numbergen.RandomDistribution: seed

+
+
+
choices = param.List(allow_refs=False, bounds=(0, None), default=[0, 1], label=’Choices’, nested_refs=False, rx=<param.reactive.reactive_ops object at 0x7f8934554e20>)

List of items from which to select.

+
+
+
+ +
+
+class numbergen.ExponentialDecay(*, base, ending_value, starting_value, time_constant, time_dependent, time_fn, name)[source]#
+

Bases: NumberGenerator, TimeDependent

+

Function object that provides a value that decays according to an +exponential function, based on a given time function.

+

Returns starting_value*base^(-time/time_constant).

+

See http://en.wikipedia.org/wiki/Exponential_decay.

+

Parameters inherited from:

+
+

numbergen.TimeAware: time_fn

+

numbergen.TimeDependent: time_dependent

+
+
+
starting_value = param.Number(allow_refs=False, default=1.0, inclusive_bounds=(True, True), label=’Starting value’, nested_refs=False, rx=<param.reactive.reactive_ops object at 0x7f893457ef10>)

Value used for time zero.

+
+
ending_value = param.Number(allow_refs=False, default=0.0, inclusive_bounds=(True, True), label=’Ending value’, nested_refs=False, rx=<param.reactive.reactive_ops object at 0x7f89344ef910>)

Value used for time infinity.

+
+
time_constant = param.Number(allow_refs=False, default=10000, inclusive_bounds=(True, True), label=’Time constant’, nested_refs=False, rx=<param.reactive.reactive_ops object at 0x7f893457e820>)

Time scale for the exponential; large values give slow decay.

+
+
base = param.Number(allow_refs=False, default=2.718281828459045, inclusive_bounds=(True, True), label=’Base’, nested_refs=False, rx=<param.reactive.reactive_ops object at 0x7f89344ef910>)

Base of the exponent; the default yields starting_value*exp(-t/time_constant). + Another popular choice of base is 2, which allows the + time_constant to be interpreted as a half-life.

+
+
+
+ +
+
+class numbergen.NormalRandom(*, mu, sigma, seed, random_generator, time_dependent, time_fn, name)[source]#
+

Bases: RandomDistribution

+

Normally distributed (Gaussian) random number.

+

Specified with mean mu and standard deviation sigma. +See the random module for further details.

+

Parameters inherited from:

+
+

numbergen.TimeAware: time_dependent, time_fn

+

numbergen.TimeAwareRandomState: random_generator

+

numbergen.RandomDistribution: seed

+
+
+
mu = param.Number(allow_refs=False, default=0.0, inclusive_bounds=(True, True), label=’Mu’, nested_refs=False, rx=<param.reactive.reactive_ops object at 0x7f89344d56d0>)

Mean value.

+
+
sigma = param.Number(allow_refs=False, bounds=(0.0, None), default=1.0, inclusive_bounds=(True, True), label=’Sigma’, nested_refs=False, rx=<param.reactive.reactive_ops object at 0x7f89344d5bb0>)

Standard deviation.

+
+
+
+ +
+
+class numbergen.NumberGenerator(*, name)[source]#
+

Bases: Parameterized

+

Abstract base class for any object that when called produces a number.

+

Primarily provides support for using NumberGenerators in simple +arithmetic expressions, such as abs((x+y)/z), where x,y,z are +NumberGenerators or numbers.

+
+ +
+
+class numbergen.RandomDistribution(*, seed, random_generator, time_dependent, time_fn, name)[source]#
+

Bases: NumberGenerator, TimeAwareRandomState

+

The base class for all Numbergenerators using random state.

+

Numbergen provides a hierarchy of classes to make it easier to use +the random distributions made available in Python’s random module, +where each class is tied to a particular random distribution.

+

RandomDistributions support setting parameters on creation rather +than passing them each call, and allow pickling to work properly. +Code that uses these classes will be independent of how many +parameters are used by the underlying distribution, and can simply +treat them as a generic source of random numbers.

+

RandomDistributions are examples of TimeAwareRandomState, and thus +can be locked to a global time if desired. By default, +time_dependent=False, and so a new random value will be generated +each time these objects are called. If you have a global time +function, you can set time_dependent=True, so that the random +values will instead be constant at any given time, changing only +when the time changes. Using time_dependent values can help you +obtain fully reproducible streams of random numbers, even if you +e.g. move time forwards and backwards for testing.

+

Note: Each RandomDistribution object has independent random state.

+

Parameters inherited from:

+
+

numbergen.TimeAware: time_dependent, time_fn

+

numbergen.TimeAwareRandomState: random_generator

+
+
+
seed = param.Integer(allow_None=True, allow_refs=False, inclusive_bounds=(True, True), label=’Seed’, nested_refs=False, rx=<param.reactive.reactive_ops object at 0x7f89345385e0>)

Sets the seed of the random number generator and can be used to + randomize time dependent streams. + + If seed is None, there is no control over the random stream + (i.e. no reproducibility of the stream).

+
+
+
+ +
+
+class numbergen.ScaledTime(*, factor, time_dependent, time_fn, name)[source]#
+

Bases: NumberGenerator, TimeDependent

+

The current time multiplied by some conversion factor.

+

Parameters inherited from:

+
+

numbergen.TimeAware: time_fn

+

numbergen.TimeDependent: time_dependent

+
+
+
factor = param.Number(allow_refs=False, default=1.0, inclusive_bounds=(True, True), label=’Factor’, nested_refs=False, rx=<param.reactive.reactive_ops object at 0x7f89344cf760>)

The factor to be multiplied by the current time value.

+
+
+
+ +
+
+class numbergen.SquareWave(*, duration, off_duration, onset, time_dependent, time_fn, name)[source]#
+

Bases: NumberGenerator, TimeDependent

+

Generate a square wave with ‘on’ periods returning 1.0 and +‘off’periods returning 0.0 of specified duration(s). By default +the portion of time spent in the high state matches the time spent +in the low state (a duty cycle of 50%), but the duty cycle can be +controlled if desired.

+

The ‘on’ state begins after a time specified by the ‘onset’ +parameter. The onset duration supplied must be less than the off +duration.

+

Parameters inherited from:

+
+

numbergen.TimeAware: time_fn

+

numbergen.TimeDependent: time_dependent

+
+
+
onset = param.Number(allow_refs=False, default=0.0, inclusive_bounds=(True, True), label=’Onset’, nested_refs=False, rx=<param.reactive.reactive_ops object at 0x7f893452c7c0>)

Time of onset of the first ‘on’ + state relative to time 0. Must be set to a value less than the + ‘off_duration’ parameter.

+
+
duration = param.Number(allow_refs=False, bounds=(0.0, None), default=1.0, inclusive_bounds=(True, True), label=’Duration’, nested_refs=False, rx=<param.reactive.reactive_ops object at 0x7f893452c490>)

Duration of the ‘on’ state during which a value of 1.0 is + returned.

+
+
off_duration = param.Number(allow_None=True, allow_refs=False, bounds=(0.0, None), inclusive_bounds=(True, True), label=’Off duration’, nested_refs=False, rx=<param.reactive.reactive_ops object at 0x7f893452c820>)

Duration of the ‘off’ value state during which a value of 0.0 + is returned. By default, this duration matches the value of + the ‘duration’ parameter.

+
+
+
+ +
+
+class numbergen.TimeSampledFn(*, fn, offset, period, time_dependent, time_fn, name)[source]#
+

Bases: NumberGenerator, TimeDependent

+

Samples the values supplied by a time_dependent callable at +regular intervals of duration ‘period’, with the sampled value +held constant within each interval.

+

Parameters inherited from:

+
+

numbergen.TimeAware: time_fn

+

numbergen.TimeDependent: time_dependent

+
+
+
period = param.Number(allow_refs=False, bounds=(0.0, None), default=1.0, inclusive_bounds=(False, True), label=’Period’, nested_refs=False, rx=<param.reactive.reactive_ops object at 0x7f89344c0910>, softbounds=(0.0, 5.0))

The periodicity with which the values of fn are sampled.

+
+
offset = param.Number(allow_refs=False, bounds=(0.0, None), default=0.0, inclusive_bounds=(True, True), label=’Offset’, nested_refs=False, rx=<param.reactive.reactive_ops object at 0x7f89345f2e80>, softbounds=(0.0, 5.0))

The offset from time 0.0 at which the first sample will be drawn. + Must be less than the value of period.

+
+
fn = param.Callable(allow_None=True, allow_refs=False, label=’Fn’, nested_refs=False, rx=<param.reactive.reactive_ops object at 0x7f89344c0d30>)

The time-dependent function used to generate the sampled values.

+
+
+
+ +
+
+class numbergen.UnaryOperator(operand, operator, **args)[source]#
+

Bases: NumberGenerator

+

Applies any unary operator to a NumberGenerator to yield another NumberGenerator.

+
+ +
+
+class numbergen.UniformRandom(*, lbound, ubound, seed, random_generator, time_dependent, time_fn, name)[source]#
+

Bases: RandomDistribution

+

Specified with lbound and ubound; when called, return a random +number in the range [lbound, ubound).

+

See the random module for further details.

+

Parameters inherited from:

+
+

numbergen.TimeAware: time_dependent, time_fn

+

numbergen.TimeAwareRandomState: random_generator

+

numbergen.RandomDistribution: seed

+
+
+
lbound = param.Number(allow_refs=False, default=0.0, inclusive_bounds=(True, True), label=’Lbound’, nested_refs=False, rx=<param.reactive.reactive_ops object at 0x7f8934547580>)

Inclusive lower bound.

+
+
ubound = param.Number(allow_refs=False, default=1.0, inclusive_bounds=(True, True), label=’Ubound’, nested_refs=False, rx=<param.reactive.reactive_ops object at 0x7f89345f2160>)

Exclusive upper bound.

+
+
+
+ +
+
+class numbergen.UniformRandomInt(*, lbound, ubound, seed, random_generator, time_dependent, time_fn, name)[source]#
+

Bases: RandomDistribution

+

Specified with lbound and ubound; when called, return a random +number in the inclusive range [lbound, ubound].

+

See the randint function in the random module for further details.

+

Parameters inherited from:

+
+

numbergen.TimeAware: time_dependent, time_fn

+

numbergen.TimeAwareRandomState: random_generator

+

numbergen.RandomDistribution: seed

+
+
+
lbound = param.Number(allow_refs=False, default=0, inclusive_bounds=(True, True), label=’Lbound’, nested_refs=False, rx=<param.reactive.reactive_ops object at 0x7f8934547460>)

Inclusive lower bound.

+
+
ubound = param.Number(allow_refs=False, default=1000, inclusive_bounds=(True, True), label=’Ubound’, nested_refs=False, rx=<param.reactive.reactive_ops object at 0x7f893454e1c0>)

Inclusive upper bound.

+
+
+
+ +
+
+class numbergen.UniformRandomOffset(*, mean, range, seed, random_generator, time_dependent, time_fn, name)[source]#
+

Bases: RandomDistribution

+

Identical to UniformRandom, but specified by mean and range. +When called, return a random number in the range +[mean - range/2, mean + range/2).

+

See the random module for further details.

+

Parameters inherited from:

+
+

numbergen.TimeAware: time_dependent, time_fn

+

numbergen.TimeAwareRandomState: random_generator

+

numbergen.RandomDistribution: seed

+
+
+
mean = param.Number(allow_refs=False, default=0.0, inclusive_bounds=(True, True), label=’Mean’, nested_refs=False, rx=<param.reactive.reactive_ops object at 0x7f89344049a0>)

Mean value

+
+
range = param.Number(allow_refs=False, bounds=(0.0, None), default=1.0, inclusive_bounds=(True, True), label=’Range’, nested_refs=False, rx=<param.reactive.reactive_ops object at 0x7f8934404be0>)

Difference of maximum and minimum value

+
+
+
+ +
+
+class numbergen.VonMisesRandom(*, kappa, mu, seed, random_generator, time_dependent, time_fn, name)[source]#
+

Bases: RandomDistribution

+

Circularly normal distributed random number.

+

If kappa is zero, this distribution reduces to a uniform random +angle over the range 0 to 2*pi. Otherwise, it is concentrated to +a greater or lesser degree (determined by kappa) around the mean +mu. For large kappa (narrow peaks), this distribution approaches +the Gaussian (normal) distribution with variance 1/kappa. See the +random module for further details.

+

Parameters inherited from:

+
+

numbergen.TimeAware: time_dependent, time_fn

+

numbergen.TimeAwareRandomState: random_generator

+

numbergen.RandomDistribution: seed

+
+
+
mu = param.Number(allow_refs=False, default=0.0, inclusive_bounds=(True, True), label=’Mu’, nested_refs=False, rx=<param.reactive.reactive_ops object at 0x7f8934409940>, softbounds=(0.0, 6.283185307179586))

Mean value, typically in the range 0 to 2*pi.

+
+
kappa = param.Number(allow_refs=False, bounds=(0.0, None), default=1.0, inclusive_bounds=(True, True), label=’Kappa’, nested_refs=False, rx=<param.reactive.reactive_ops object at 0x7f8934409b80>, softbounds=(0.0, 50.0))

Concentration (inverse variance).

+
+
+
+ +
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.Action.html b/reference/param/generated/param.Action.html new file mode 100644 index 0000000..2f98eab --- /dev/null +++ b/reference/param/generated/param.Action.html @@ -0,0 +1,856 @@ + + + + + + + + + + + + param.Action — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.Action#

+
+
+class param.Action(default=None, *, doc=None, label=None, precedence=None, instantiate=False, constant=False, readonly=False, pickle_default_value=True, allow_None=False, per_instance=True, allow_refs=False, nested_refs=False)[source]#
+

A user-provided function that can be invoked like a class or object method using (). +In a GUI, this might be mapped to a button, but it can be invoked directly as well.

+
+
+__init__(default=<Undefined>, **params)#
+

Initialize a new Parameter object and store the supplied attributes:

+

default: the owning class’s value for the attribute represented +by this Parameter, which can be overridden in an instance.

+

doc: docstring explaining what this parameter represents.

+

label: optional text label to be used when this Parameter is +shown in a listing. If no label is supplied, the attribute name +for this parameter in the owning Parameterized object is used.

+

precedence: a numeric value, usually in the range 0.0 to 1.0, +which allows the order of Parameters in a class to be defined in +a listing or e.g. in GUI menus. A negative precedence indicates +a parameter that should be hidden in such listings.

+

instantiate: controls whether the value of this Parameter will +be deepcopied when a Parameterized object is instantiated (if +True), or if the single default value will be shared by all +Parameterized instances (if False). For an immutable Parameter +value, it is best to leave instantiate at the default of +False, so that a user can choose to change the value at the +Parameterized instance level (affecting only that instance) or +at the Parameterized class or superclass level (affecting all +existing and future instances of that class or superclass). For +a mutable Parameter value, the default of False is also appropriate +if you want all instances to share the same value state, e.g. if +they are each simply referring to a single global object like +a singleton. If instead each Parameterized should have its own +independently mutable value, instantiate should be set to +True, but note that there is then no simple way to change the +value of this Parameter at the class or superclass level, +because each instance, once created, will then have an +independently instantiated value.

+

constant: if true, the Parameter value can be changed only at +the class level or in a Parameterized constructor call. The +value is otherwise constant on the Parameterized instance, +once it has been constructed.

+

readonly: if true, the Parameter value cannot ordinarily be +changed by setting the attribute at the class or instance +levels at all. The value can still be changed in code by +temporarily overriding the value of this slot and then +restoring it, which is useful for reporting values that the +_user_ should never change but which do change during code +execution.

+

pickle_default_value: whether the default value should be +pickled. Usually, you would want the default value to be pickled, +but there are rare cases where that would not be the case (e.g. +for file search paths that are specific to a certain system).

+

per_instance: whether a separate Parameter instance will be +created for every Parameterized instance. True by default. +If False, all instances of a Parameterized class will share +the same Parameter object, including all validation +attributes (bounds, etc.). See also instantiate, which is +conceptually similar but affects the Parameter value rather +than the Parameter object.

+

allow_None: if True, None is accepted as a valid value for +this Parameter, in addition to any other values that are +allowed. If the default value is defined as None, allow_None +is set to True automatically.

+

allow_refs: if True allows automatically linking parameter +references to this Parameter, i.e. the parameter value will +automatically reflect the current value of the reference that +is passed in.

+

nested_refs: if True and allow_refs=True then even nested objects +such as dictionaries, lists, slices, tuples and sets will be +inspected for references and will be automatically resolved.

+

default, doc, and precedence all default to None, which allows +inheritance of Parameter slots (attributes) from the owning-class’ +class hierarchy (see ParameterizedMetaclass).

+
+ +

Methods

+ + + + + + + + + + + + + + + +

__init__([default])

Initialize a new Parameter object and store the supplied attributes:

deserialize(value)

Given a serializable Python value, return a value that the parameter can be set to

schema([safe, subset, mode])

serialize(value)

Given the parameter value, return a Python value suitable for serialization

+

Attributes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

allow_None

allow_refs

constant

default

doc

instantiate

label

name

nested_refs

owner

per_instance

pickle_default_value

precedence

readonly

rx

watchers

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.Array.html b/reference/param/generated/param.Array.html new file mode 100644 index 0000000..595905b --- /dev/null +++ b/reference/param/generated/param.Array.html @@ -0,0 +1,864 @@ + + + + + + + + + + + + param.Array — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.Array#

+
+
+class param.Array(default=None, *, instantiate=True, is_instance=True, doc=None, label=None, precedence=None, constant=False, readonly=False, pickle_default_value=True, allow_None=False, per_instance=True, allow_refs=False, nested_refs=False)[source]#
+

Parameter whose value is a numpy array.

+
+
+__init__(default=None, *, is_instance=True, allow_None=False, doc=None, label=None, precedence=None, instantiate=True, constant=False, readonly=False, pickle_default_value=True, per_instance=True, allow_refs=False, nested_refs=False)[source]#
+

Initialize a new Parameter object and store the supplied attributes:

+

default: the owning class’s value for the attribute represented +by this Parameter, which can be overridden in an instance.

+

doc: docstring explaining what this parameter represents.

+

label: optional text label to be used when this Parameter is +shown in a listing. If no label is supplied, the attribute name +for this parameter in the owning Parameterized object is used.

+

precedence: a numeric value, usually in the range 0.0 to 1.0, +which allows the order of Parameters in a class to be defined in +a listing or e.g. in GUI menus. A negative precedence indicates +a parameter that should be hidden in such listings.

+

instantiate: controls whether the value of this Parameter will +be deepcopied when a Parameterized object is instantiated (if +True), or if the single default value will be shared by all +Parameterized instances (if False). For an immutable Parameter +value, it is best to leave instantiate at the default of +False, so that a user can choose to change the value at the +Parameterized instance level (affecting only that instance) or +at the Parameterized class or superclass level (affecting all +existing and future instances of that class or superclass). For +a mutable Parameter value, the default of False is also appropriate +if you want all instances to share the same value state, e.g. if +they are each simply referring to a single global object like +a singleton. If instead each Parameterized should have its own +independently mutable value, instantiate should be set to +True, but note that there is then no simple way to change the +value of this Parameter at the class or superclass level, +because each instance, once created, will then have an +independently instantiated value.

+

constant: if true, the Parameter value can be changed only at +the class level or in a Parameterized constructor call. The +value is otherwise constant on the Parameterized instance, +once it has been constructed.

+

readonly: if true, the Parameter value cannot ordinarily be +changed by setting the attribute at the class or instance +levels at all. The value can still be changed in code by +temporarily overriding the value of this slot and then +restoring it, which is useful for reporting values that the +_user_ should never change but which do change during code +execution.

+

pickle_default_value: whether the default value should be +pickled. Usually, you would want the default value to be pickled, +but there are rare cases where that would not be the case (e.g. +for file search paths that are specific to a certain system).

+

per_instance: whether a separate Parameter instance will be +created for every Parameterized instance. True by default. +If False, all instances of a Parameterized class will share +the same Parameter object, including all validation +attributes (bounds, etc.). See also instantiate, which is +conceptually similar but affects the Parameter value rather +than the Parameter object.

+

allow_None: if True, None is accepted as a valid value for +this Parameter, in addition to any other values that are +allowed. If the default value is defined as None, allow_None +is set to True automatically.

+

allow_refs: if True allows automatically linking parameter +references to this Parameter, i.e. the parameter value will +automatically reflect the current value of the reference that +is passed in.

+

nested_refs: if True and allow_refs=True then even nested objects +such as dictionaries, lists, slices, tuples and sets will be +inspected for references and will be automatically resolved.

+

default, doc, and precedence all default to None, which allows +inheritance of Parameter slots (attributes) from the owning-class’ +class hierarchy (see ParameterizedMetaclass).

+
+ +

Methods

+ + + + + + + + + + + + + + + + + + +

__init__([default, is_instance, allow_None, ...])

Initialize a new Parameter object and store the supplied attributes:

deserialize(value)

Given a serializable Python value, return a value that the parameter can be set to

get_range()

Return the possible types for this parameter's value.

schema([safe, subset, mode])

serialize(value)

Given the parameter value, return a Python value suitable for serialization

+

Attributes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

allow_None

allow_refs

class_

constant

default

doc

instantiate

is_instance

label

name

nested_refs

owner

per_instance

pickle_default_value

precedence

readonly

rx

watchers

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.Boolean.html b/reference/param/generated/param.Boolean.html new file mode 100644 index 0000000..999a509 --- /dev/null +++ b/reference/param/generated/param.Boolean.html @@ -0,0 +1,855 @@ + + + + + + + + + + + + param.Boolean — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.Boolean#

+
+
+class param.Boolean(default=False, *, doc=None, label=None, precedence=None, instantiate=False, constant=False, readonly=False, pickle_default_value=True, allow_None=False, per_instance=True, allow_refs=False, nested_refs=False)[source]#
+

Binary or tristate Boolean Parameter.

+
+
+__init__(default=False, *, allow_None=False, doc=None, label=None, precedence=None, instantiate=False, constant=False, readonly=False, pickle_default_value=True, per_instance=True, allow_refs=False, nested_refs=False)[source]#
+

Initialize a new Parameter object and store the supplied attributes:

+

default: the owning class’s value for the attribute represented +by this Parameter, which can be overridden in an instance.

+

doc: docstring explaining what this parameter represents.

+

label: optional text label to be used when this Parameter is +shown in a listing. If no label is supplied, the attribute name +for this parameter in the owning Parameterized object is used.

+

precedence: a numeric value, usually in the range 0.0 to 1.0, +which allows the order of Parameters in a class to be defined in +a listing or e.g. in GUI menus. A negative precedence indicates +a parameter that should be hidden in such listings.

+

instantiate: controls whether the value of this Parameter will +be deepcopied when a Parameterized object is instantiated (if +True), or if the single default value will be shared by all +Parameterized instances (if False). For an immutable Parameter +value, it is best to leave instantiate at the default of +False, so that a user can choose to change the value at the +Parameterized instance level (affecting only that instance) or +at the Parameterized class or superclass level (affecting all +existing and future instances of that class or superclass). For +a mutable Parameter value, the default of False is also appropriate +if you want all instances to share the same value state, e.g. if +they are each simply referring to a single global object like +a singleton. If instead each Parameterized should have its own +independently mutable value, instantiate should be set to +True, but note that there is then no simple way to change the +value of this Parameter at the class or superclass level, +because each instance, once created, will then have an +independently instantiated value.

+

constant: if true, the Parameter value can be changed only at +the class level or in a Parameterized constructor call. The +value is otherwise constant on the Parameterized instance, +once it has been constructed.

+

readonly: if true, the Parameter value cannot ordinarily be +changed by setting the attribute at the class or instance +levels at all. The value can still be changed in code by +temporarily overriding the value of this slot and then +restoring it, which is useful for reporting values that the +_user_ should never change but which do change during code +execution.

+

pickle_default_value: whether the default value should be +pickled. Usually, you would want the default value to be pickled, +but there are rare cases where that would not be the case (e.g. +for file search paths that are specific to a certain system).

+

per_instance: whether a separate Parameter instance will be +created for every Parameterized instance. True by default. +If False, all instances of a Parameterized class will share +the same Parameter object, including all validation +attributes (bounds, etc.). See also instantiate, which is +conceptually similar but affects the Parameter value rather +than the Parameter object.

+

allow_None: if True, None is accepted as a valid value for +this Parameter, in addition to any other values that are +allowed. If the default value is defined as None, allow_None +is set to True automatically.

+

allow_refs: if True allows automatically linking parameter +references to this Parameter, i.e. the parameter value will +automatically reflect the current value of the reference that +is passed in.

+

nested_refs: if True and allow_refs=True then even nested objects +such as dictionaries, lists, slices, tuples and sets will be +inspected for references and will be automatically resolved.

+

default, doc, and precedence all default to None, which allows +inheritance of Parameter slots (attributes) from the owning-class’ +class hierarchy (see ParameterizedMetaclass).

+
+ +

Methods

+ + + + + + + + + + + + + + + +

__init__([default, allow_None, doc, label, ...])

Initialize a new Parameter object and store the supplied attributes:

deserialize(value)

Given a serializable Python value, return a value that the parameter can be set to

schema([safe, subset, mode])

serialize(value)

Given the parameter value, return a Python value suitable for serialization

+

Attributes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

allow_None

allow_refs

constant

default

doc

instantiate

label

name

nested_refs

owner

per_instance

pickle_default_value

precedence

readonly

rx

watchers

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.Bytes.html b/reference/param/generated/param.Bytes.html new file mode 100644 index 0000000..baa0c6f --- /dev/null +++ b/reference/param/generated/param.Bytes.html @@ -0,0 +1,861 @@ + + + + + + + + + + + + param.Bytes — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.Bytes#

+
+
+class param.Bytes(default=b'', *, regex=None, allow_None=False, doc=None, label=None, precedence=None, instantiate=False, constant=False, readonly=False, pickle_default_value=True, per_instance=True, allow_refs=False, nested_refs=False)[source]#
+

A Bytes Parameter, with a default value and optional regular +expression (regex) matching.

+

Similar to the String parameter, but instead of type string +this parameter only allows objects of type bytes (e.g. b’bytes’).

+
+
+__init__(default=b'', *, regex=None, allow_None=False, doc=None, label=None, precedence=None, instantiate=False, constant=False, readonly=False, pickle_default_value=True, per_instance=True, allow_refs=False, nested_refs=False)[source]#
+

Initialize a new Parameter object and store the supplied attributes:

+

default: the owning class’s value for the attribute represented +by this Parameter, which can be overridden in an instance.

+

doc: docstring explaining what this parameter represents.

+

label: optional text label to be used when this Parameter is +shown in a listing. If no label is supplied, the attribute name +for this parameter in the owning Parameterized object is used.

+

precedence: a numeric value, usually in the range 0.0 to 1.0, +which allows the order of Parameters in a class to be defined in +a listing or e.g. in GUI menus. A negative precedence indicates +a parameter that should be hidden in such listings.

+

instantiate: controls whether the value of this Parameter will +be deepcopied when a Parameterized object is instantiated (if +True), or if the single default value will be shared by all +Parameterized instances (if False). For an immutable Parameter +value, it is best to leave instantiate at the default of +False, so that a user can choose to change the value at the +Parameterized instance level (affecting only that instance) or +at the Parameterized class or superclass level (affecting all +existing and future instances of that class or superclass). For +a mutable Parameter value, the default of False is also appropriate +if you want all instances to share the same value state, e.g. if +they are each simply referring to a single global object like +a singleton. If instead each Parameterized should have its own +independently mutable value, instantiate should be set to +True, but note that there is then no simple way to change the +value of this Parameter at the class or superclass level, +because each instance, once created, will then have an +independently instantiated value.

+

constant: if true, the Parameter value can be changed only at +the class level or in a Parameterized constructor call. The +value is otherwise constant on the Parameterized instance, +once it has been constructed.

+

readonly: if true, the Parameter value cannot ordinarily be +changed by setting the attribute at the class or instance +levels at all. The value can still be changed in code by +temporarily overriding the value of this slot and then +restoring it, which is useful for reporting values that the +_user_ should never change but which do change during code +execution.

+

pickle_default_value: whether the default value should be +pickled. Usually, you would want the default value to be pickled, +but there are rare cases where that would not be the case (e.g. +for file search paths that are specific to a certain system).

+

per_instance: whether a separate Parameter instance will be +created for every Parameterized instance. True by default. +If False, all instances of a Parameterized class will share +the same Parameter object, including all validation +attributes (bounds, etc.). See also instantiate, which is +conceptually similar but affects the Parameter value rather +than the Parameter object.

+

allow_None: if True, None is accepted as a valid value for +this Parameter, in addition to any other values that are +allowed. If the default value is defined as None, allow_None +is set to True automatically.

+

allow_refs: if True allows automatically linking parameter +references to this Parameter, i.e. the parameter value will +automatically reflect the current value of the reference that +is passed in.

+

nested_refs: if True and allow_refs=True then even nested objects +such as dictionaries, lists, slices, tuples and sets will be +inspected for references and will be automatically resolved.

+

default, doc, and precedence all default to None, which allows +inheritance of Parameter slots (attributes) from the owning-class’ +class hierarchy (see ParameterizedMetaclass).

+
+ +

Methods

+ + + + + + + + + + + + + + + +

__init__([default, regex, allow_None, doc, ...])

Initialize a new Parameter object and store the supplied attributes:

deserialize(value)

Given a serializable Python value, return a value that the parameter can be set to

schema([safe, subset, mode])

serialize(value)

Given the parameter value, return a Python value suitable for serialization

+

Attributes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

regex

allow_None

allow_refs

constant

default

doc

instantiate

label

name

nested_refs

owner

per_instance

pickle_default_value

precedence

readonly

rx

watchers

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.CalendarDateRange.html b/reference/param/generated/param.CalendarDateRange.html new file mode 100644 index 0000000..bb95057 --- /dev/null +++ b/reference/param/generated/param.CalendarDateRange.html @@ -0,0 +1,815 @@ + + + + + + + + + + + + param.CalendarDateRange — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.CalendarDateRange#

+
+
+class param.CalendarDateRange(default=None, *, bounds=None, softbounds=None, inclusive_bounds=(True, True), step=None, length=None, doc=None, label=None, precedence=None, instantiate=False, constant=False, readonly=False, pickle_default_value=True, allow_None=False, per_instance=True, allow_refs=False, nested_refs=False)[source]#
+

A date range specified as (start_date, end_date).

+
+
+__init__(default=<Undefined>, *, bounds=<Undefined>, softbounds=<Undefined>, inclusive_bounds=<Undefined>, step=<Undefined>, **params)#
+

Initialize a tuple parameter with a fixed length (number of +elements). The length is determined by the initial default +value, if any, and must be supplied explicitly otherwise. The +length is not allowed to change after instantiation.

+
+ +

Methods

+ + + + + + + + + + + + + + + + + + + + + +

__init__([default, bounds, softbounds, ...])

Initialize a tuple parameter with a fixed length (number of elements).

deserialize(value)

Given a serializable Python value, return a value that the parameter can be set to

get_soft_bounds()

rangestr()

schema([safe, subset, mode])

serialize(value)

Given the parameter value, return a Python value suitable for serialization

+

Attributes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

allow_None

allow_refs

bounds

constant

default

doc

inclusive_bounds

instantiate

label

length

name

nested_refs

owner

per_instance

pickle_default_value

precedence

readonly

rx

softbounds

step

watchers

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.Callable.html b/reference/param/generated/param.Callable.html new file mode 100644 index 0000000..92bfec8 --- /dev/null +++ b/reference/param/generated/param.Callable.html @@ -0,0 +1,859 @@ + + + + + + + + + + + + param.Callable — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.Callable#

+
+
+class param.Callable(default=None, *, doc=None, label=None, precedence=None, instantiate=False, constant=False, readonly=False, pickle_default_value=True, allow_None=False, per_instance=True, allow_refs=False, nested_refs=False)[source]#
+

Parameter holding a value that is a callable object, such as a function.

+

A keyword argument instantiate=True should be provided when a +function object is used that might have state. On the other hand, +regular standalone functions cannot be deepcopied as of Python +2.4, so instantiate must be False for those values.

+
+
+__init__(default=None, *, allow_None=False, doc=None, label=None, precedence=None, instantiate=False, constant=False, readonly=False, pickle_default_value=True, per_instance=True, allow_refs=False, nested_refs=False)[source]#
+

Initialize a new Parameter object and store the supplied attributes:

+

default: the owning class’s value for the attribute represented +by this Parameter, which can be overridden in an instance.

+

doc: docstring explaining what this parameter represents.

+

label: optional text label to be used when this Parameter is +shown in a listing. If no label is supplied, the attribute name +for this parameter in the owning Parameterized object is used.

+

precedence: a numeric value, usually in the range 0.0 to 1.0, +which allows the order of Parameters in a class to be defined in +a listing or e.g. in GUI menus. A negative precedence indicates +a parameter that should be hidden in such listings.

+

instantiate: controls whether the value of this Parameter will +be deepcopied when a Parameterized object is instantiated (if +True), or if the single default value will be shared by all +Parameterized instances (if False). For an immutable Parameter +value, it is best to leave instantiate at the default of +False, so that a user can choose to change the value at the +Parameterized instance level (affecting only that instance) or +at the Parameterized class or superclass level (affecting all +existing and future instances of that class or superclass). For +a mutable Parameter value, the default of False is also appropriate +if you want all instances to share the same value state, e.g. if +they are each simply referring to a single global object like +a singleton. If instead each Parameterized should have its own +independently mutable value, instantiate should be set to +True, but note that there is then no simple way to change the +value of this Parameter at the class or superclass level, +because each instance, once created, will then have an +independently instantiated value.

+

constant: if true, the Parameter value can be changed only at +the class level or in a Parameterized constructor call. The +value is otherwise constant on the Parameterized instance, +once it has been constructed.

+

readonly: if true, the Parameter value cannot ordinarily be +changed by setting the attribute at the class or instance +levels at all. The value can still be changed in code by +temporarily overriding the value of this slot and then +restoring it, which is useful for reporting values that the +_user_ should never change but which do change during code +execution.

+

pickle_default_value: whether the default value should be +pickled. Usually, you would want the default value to be pickled, +but there are rare cases where that would not be the case (e.g. +for file search paths that are specific to a certain system).

+

per_instance: whether a separate Parameter instance will be +created for every Parameterized instance. True by default. +If False, all instances of a Parameterized class will share +the same Parameter object, including all validation +attributes (bounds, etc.). See also instantiate, which is +conceptually similar but affects the Parameter value rather +than the Parameter object.

+

allow_None: if True, None is accepted as a valid value for +this Parameter, in addition to any other values that are +allowed. If the default value is defined as None, allow_None +is set to True automatically.

+

allow_refs: if True allows automatically linking parameter +references to this Parameter, i.e. the parameter value will +automatically reflect the current value of the reference that +is passed in.

+

nested_refs: if True and allow_refs=True then even nested objects +such as dictionaries, lists, slices, tuples and sets will be +inspected for references and will be automatically resolved.

+

default, doc, and precedence all default to None, which allows +inheritance of Parameter slots (attributes) from the owning-class’ +class hierarchy (see ParameterizedMetaclass).

+
+ +

Methods

+ + + + + + + + + + + + + + + +

__init__([default, allow_None, doc, label, ...])

Initialize a new Parameter object and store the supplied attributes:

deserialize(value)

Given a serializable Python value, return a value that the parameter can be set to

schema([safe, subset, mode])

serialize(value)

Given the parameter value, return a Python value suitable for serialization

+

Attributes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

allow_None

allow_refs

constant

default

doc

instantiate

label

name

nested_refs

owner

per_instance

pickle_default_value

precedence

readonly

rx

watchers

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.ClassSelector.html b/reference/param/generated/param.ClassSelector.html new file mode 100644 index 0000000..d156229 --- /dev/null +++ b/reference/param/generated/param.ClassSelector.html @@ -0,0 +1,867 @@ + + + + + + + + + + + + param.ClassSelector — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.ClassSelector#

+
+
+class param.ClassSelector(*, class_, default=None, instantiate=True, is_instance=True, doc=None, label=None, precedence=None, constant=False, readonly=False, pickle_default_value=True, allow_None=False, per_instance=True, allow_refs=False, nested_refs=False)[source]#
+

Parameter allowing selection of either a subclass or an instance of a given set of classes. +By default, requires an instance, but if is_instance=False, accepts a class instead. +Both class and instance values respect the instantiate slot, though it matters only +for is_instance=True.

+
+
+__init__(*, class_, default=None, instantiate=True, is_instance=True, allow_None=False, doc=None, label=None, precedence=None, constant=False, readonly=False, pickle_default_value=True, per_instance=True, allow_refs=False, nested_refs=False)[source]#
+

Initialize a new Parameter object and store the supplied attributes:

+

default: the owning class’s value for the attribute represented +by this Parameter, which can be overridden in an instance.

+

doc: docstring explaining what this parameter represents.

+

label: optional text label to be used when this Parameter is +shown in a listing. If no label is supplied, the attribute name +for this parameter in the owning Parameterized object is used.

+

precedence: a numeric value, usually in the range 0.0 to 1.0, +which allows the order of Parameters in a class to be defined in +a listing or e.g. in GUI menus. A negative precedence indicates +a parameter that should be hidden in such listings.

+

instantiate: controls whether the value of this Parameter will +be deepcopied when a Parameterized object is instantiated (if +True), or if the single default value will be shared by all +Parameterized instances (if False). For an immutable Parameter +value, it is best to leave instantiate at the default of +False, so that a user can choose to change the value at the +Parameterized instance level (affecting only that instance) or +at the Parameterized class or superclass level (affecting all +existing and future instances of that class or superclass). For +a mutable Parameter value, the default of False is also appropriate +if you want all instances to share the same value state, e.g. if +they are each simply referring to a single global object like +a singleton. If instead each Parameterized should have its own +independently mutable value, instantiate should be set to +True, but note that there is then no simple way to change the +value of this Parameter at the class or superclass level, +because each instance, once created, will then have an +independently instantiated value.

+

constant: if true, the Parameter value can be changed only at +the class level or in a Parameterized constructor call. The +value is otherwise constant on the Parameterized instance, +once it has been constructed.

+

readonly: if true, the Parameter value cannot ordinarily be +changed by setting the attribute at the class or instance +levels at all. The value can still be changed in code by +temporarily overriding the value of this slot and then +restoring it, which is useful for reporting values that the +_user_ should never change but which do change during code +execution.

+

pickle_default_value: whether the default value should be +pickled. Usually, you would want the default value to be pickled, +but there are rare cases where that would not be the case (e.g. +for file search paths that are specific to a certain system).

+

per_instance: whether a separate Parameter instance will be +created for every Parameterized instance. True by default. +If False, all instances of a Parameterized class will share +the same Parameter object, including all validation +attributes (bounds, etc.). See also instantiate, which is +conceptually similar but affects the Parameter value rather +than the Parameter object.

+

allow_None: if True, None is accepted as a valid value for +this Parameter, in addition to any other values that are +allowed. If the default value is defined as None, allow_None +is set to True automatically.

+

allow_refs: if True allows automatically linking parameter +references to this Parameter, i.e. the parameter value will +automatically reflect the current value of the reference that +is passed in.

+

nested_refs: if True and allow_refs=True then even nested objects +such as dictionaries, lists, slices, tuples and sets will be +inspected for references and will be automatically resolved.

+

default, doc, and precedence all default to None, which allows +inheritance of Parameter slots (attributes) from the owning-class’ +class hierarchy (see ParameterizedMetaclass).

+
+ +

Methods

+ + + + + + + + + + + + + + + + + + +

__init__(*, class_[, default, instantiate, ...])

Initialize a new Parameter object and store the supplied attributes:

deserialize(value)

Given a serializable Python value, return a value that the parameter can be set to

get_range()

Return the possible types for this parameter's value.

schema([safe, subset, mode])

serialize(value)

Given the parameter value, return a Python value suitable for serialization

+

Attributes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

class_

is_instance

allow_None

allow_refs

constant

default

doc

instantiate

label

name

nested_refs

owner

per_instance

pickle_default_value

precedence

readonly

rx

watchers

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.Color.html b/reference/param/generated/param.Color.html new file mode 100644 index 0000000..244205d --- /dev/null +++ b/reference/param/generated/param.Color.html @@ -0,0 +1,859 @@ + + + + + + + + + + + + param.Color — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.Color#

+
+
+class param.Color(default=None, *, allow_named=True, doc=None, label=None, precedence=None, instantiate=False, constant=False, readonly=False, pickle_default_value=True, allow_None=False, per_instance=True, allow_refs=False, nested_refs=False)[source]#
+

Color parameter defined as a hex RGB string with an optional # +prefix or (optionally) as a CSS3 color name.

+
+
+__init__(default=None, *, allow_named=True, allow_None=False, doc=None, label=None, precedence=None, instantiate=False, constant=False, readonly=False, pickle_default_value=True, per_instance=True, allow_refs=False, nested_refs=False)[source]#
+

Initialize a new Parameter object and store the supplied attributes:

+

default: the owning class’s value for the attribute represented +by this Parameter, which can be overridden in an instance.

+

doc: docstring explaining what this parameter represents.

+

label: optional text label to be used when this Parameter is +shown in a listing. If no label is supplied, the attribute name +for this parameter in the owning Parameterized object is used.

+

precedence: a numeric value, usually in the range 0.0 to 1.0, +which allows the order of Parameters in a class to be defined in +a listing or e.g. in GUI menus. A negative precedence indicates +a parameter that should be hidden in such listings.

+

instantiate: controls whether the value of this Parameter will +be deepcopied when a Parameterized object is instantiated (if +True), or if the single default value will be shared by all +Parameterized instances (if False). For an immutable Parameter +value, it is best to leave instantiate at the default of +False, so that a user can choose to change the value at the +Parameterized instance level (affecting only that instance) or +at the Parameterized class or superclass level (affecting all +existing and future instances of that class or superclass). For +a mutable Parameter value, the default of False is also appropriate +if you want all instances to share the same value state, e.g. if +they are each simply referring to a single global object like +a singleton. If instead each Parameterized should have its own +independently mutable value, instantiate should be set to +True, but note that there is then no simple way to change the +value of this Parameter at the class or superclass level, +because each instance, once created, will then have an +independently instantiated value.

+

constant: if true, the Parameter value can be changed only at +the class level or in a Parameterized constructor call. The +value is otherwise constant on the Parameterized instance, +once it has been constructed.

+

readonly: if true, the Parameter value cannot ordinarily be +changed by setting the attribute at the class or instance +levels at all. The value can still be changed in code by +temporarily overriding the value of this slot and then +restoring it, which is useful for reporting values that the +_user_ should never change but which do change during code +execution.

+

pickle_default_value: whether the default value should be +pickled. Usually, you would want the default value to be pickled, +but there are rare cases where that would not be the case (e.g. +for file search paths that are specific to a certain system).

+

per_instance: whether a separate Parameter instance will be +created for every Parameterized instance. True by default. +If False, all instances of a Parameterized class will share +the same Parameter object, including all validation +attributes (bounds, etc.). See also instantiate, which is +conceptually similar but affects the Parameter value rather +than the Parameter object.

+

allow_None: if True, None is accepted as a valid value for +this Parameter, in addition to any other values that are +allowed. If the default value is defined as None, allow_None +is set to True automatically.

+

allow_refs: if True allows automatically linking parameter +references to this Parameter, i.e. the parameter value will +automatically reflect the current value of the reference that +is passed in.

+

nested_refs: if True and allow_refs=True then even nested objects +such as dictionaries, lists, slices, tuples and sets will be +inspected for references and will be automatically resolved.

+

default, doc, and precedence all default to None, which allows +inheritance of Parameter slots (attributes) from the owning-class’ +class hierarchy (see ParameterizedMetaclass).

+
+ +

Methods

+ + + + + + + + + + + + + + + +

__init__([default, allow_named, allow_None, ...])

Initialize a new Parameter object and store the supplied attributes:

deserialize(value)

Given a serializable Python value, return a value that the parameter can be set to

schema([safe, subset, mode])

serialize(value)

Given the parameter value, return a Python value suitable for serialization

+

Attributes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

allow_named

allow_None

allow_refs

constant

default

doc

instantiate

label

name

nested_refs

owner

per_instance

pickle_default_value

precedence

readonly

rx

watchers

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.Composite.html b/reference/param/generated/param.Composite.html new file mode 100644 index 0000000..2bbb003 --- /dev/null +++ b/reference/param/generated/param.Composite.html @@ -0,0 +1,869 @@ + + + + + + + + + + + + param.Composite — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.Composite#

+
+
+class param.Composite(self, *, attribs=<Undefined>, **kw)[source]#
+

A Parameter that is a composite of a set of other attributes of the class.

+

The constructor argument ‘attribs’ takes a list of attribute +names, which may or may not be Parameters. Getting the parameter +returns a list of the values of the constituents of the composite, +in the order specified. Likewise, setting the parameter takes a +sequence of values and sets the value of the constituent +attributes.

+

This Parameter type has not been tested with watchers and +dependencies, and may not support them properly.

+
+
+__init__(*, attribs=None, allow_None=False, doc=None, label=None, precedence=None, instantiate=False, constant=False, readonly=False, pickle_default_value=True, per_instance=True, allow_refs=False, nested_refs=False)[source]#
+

Initialize a new Parameter object and store the supplied attributes:

+

default: the owning class’s value for the attribute represented +by this Parameter, which can be overridden in an instance.

+

doc: docstring explaining what this parameter represents.

+

label: optional text label to be used when this Parameter is +shown in a listing. If no label is supplied, the attribute name +for this parameter in the owning Parameterized object is used.

+

precedence: a numeric value, usually in the range 0.0 to 1.0, +which allows the order of Parameters in a class to be defined in +a listing or e.g. in GUI menus. A negative precedence indicates +a parameter that should be hidden in such listings.

+

instantiate: controls whether the value of this Parameter will +be deepcopied when a Parameterized object is instantiated (if +True), or if the single default value will be shared by all +Parameterized instances (if False). For an immutable Parameter +value, it is best to leave instantiate at the default of +False, so that a user can choose to change the value at the +Parameterized instance level (affecting only that instance) or +at the Parameterized class or superclass level (affecting all +existing and future instances of that class or superclass). For +a mutable Parameter value, the default of False is also appropriate +if you want all instances to share the same value state, e.g. if +they are each simply referring to a single global object like +a singleton. If instead each Parameterized should have its own +independently mutable value, instantiate should be set to +True, but note that there is then no simple way to change the +value of this Parameter at the class or superclass level, +because each instance, once created, will then have an +independently instantiated value.

+

constant: if true, the Parameter value can be changed only at +the class level or in a Parameterized constructor call. The +value is otherwise constant on the Parameterized instance, +once it has been constructed.

+

readonly: if true, the Parameter value cannot ordinarily be +changed by setting the attribute at the class or instance +levels at all. The value can still be changed in code by +temporarily overriding the value of this slot and then +restoring it, which is useful for reporting values that the +_user_ should never change but which do change during code +execution.

+

pickle_default_value: whether the default value should be +pickled. Usually, you would want the default value to be pickled, +but there are rare cases where that would not be the case (e.g. +for file search paths that are specific to a certain system).

+

per_instance: whether a separate Parameter instance will be +created for every Parameterized instance. True by default. +If False, all instances of a Parameterized class will share +the same Parameter object, including all validation +attributes (bounds, etc.). See also instantiate, which is +conceptually similar but affects the Parameter value rather +than the Parameter object.

+

allow_None: if True, None is accepted as a valid value for +this Parameter, in addition to any other values that are +allowed. If the default value is defined as None, allow_None +is set to True automatically.

+

allow_refs: if True allows automatically linking parameter +references to this Parameter, i.e. the parameter value will +automatically reflect the current value of the reference that +is passed in.

+

nested_refs: if True and allow_refs=True then even nested objects +such as dictionaries, lists, slices, tuples and sets will be +inspected for references and will be automatically resolved.

+

default, doc, and precedence all default to None, which allows +inheritance of Parameter slots (attributes) from the owning-class’ +class hierarchy (see ParameterizedMetaclass).

+
+ +

Methods

+ + + + + + + + + + + + + + + +

__init__(*[, attribs, allow_None, doc, ...])

Initialize a new Parameter object and store the supplied attributes:

deserialize(value)

Given a serializable Python value, return a value that the parameter can be set to

schema([safe, subset, mode])

serialize(value)

Given the parameter value, return a Python value suitable for serialization

+

Attributes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

attribs

objtype

allow_None

allow_refs

constant

default

doc

instantiate

label

name

nested_refs

owner

per_instance

pickle_default_value

precedence

readonly

rx

watchers

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.DataFrame.html b/reference/param/generated/param.DataFrame.html new file mode 100644 index 0000000..043b218 --- /dev/null +++ b/reference/param/generated/param.DataFrame.html @@ -0,0 +1,884 @@ + + + + + + + + + + + + param.DataFrame — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.DataFrame#

+
+
+class param.DataFrame(default=None, *, rows=None, columns=None, ordered=None, instantiate=True, is_instance=True, doc=None, label=None, precedence=None, constant=False, readonly=False, pickle_default_value=True, allow_None=False, per_instance=True, allow_refs=False, nested_refs=False)[source]#
+

Parameter whose value is a pandas DataFrame.

+

The structure of the DataFrame can be constrained by the rows and +columns arguments:

+

rows: If specified, may be a number or an integer bounds tuple to +constrain the allowable number of rows.

+

columns: If specified, may be a number, an integer bounds tuple, a +list or a set. If the argument is numeric, constrains the number of +columns using the same semantics as used for rows. If either a list +or set of strings, the column names will be validated. If a set is +used, the supplied DataFrame must contain the specified columns and +if a list is given, the supplied DataFrame must contain exactly the +same columns and in the same order and no other columns.

+
+
+__init__(default=None, *, rows=None, columns=None, ordered=None, is_instance=True, allow_None=False, doc=None, label=None, precedence=None, instantiate=True, constant=False, readonly=False, pickle_default_value=True, per_instance=True, allow_refs=False, nested_refs=False)[source]#
+

Initialize a new Parameter object and store the supplied attributes:

+

default: the owning class’s value for the attribute represented +by this Parameter, which can be overridden in an instance.

+

doc: docstring explaining what this parameter represents.

+

label: optional text label to be used when this Parameter is +shown in a listing. If no label is supplied, the attribute name +for this parameter in the owning Parameterized object is used.

+

precedence: a numeric value, usually in the range 0.0 to 1.0, +which allows the order of Parameters in a class to be defined in +a listing or e.g. in GUI menus. A negative precedence indicates +a parameter that should be hidden in such listings.

+

instantiate: controls whether the value of this Parameter will +be deepcopied when a Parameterized object is instantiated (if +True), or if the single default value will be shared by all +Parameterized instances (if False). For an immutable Parameter +value, it is best to leave instantiate at the default of +False, so that a user can choose to change the value at the +Parameterized instance level (affecting only that instance) or +at the Parameterized class or superclass level (affecting all +existing and future instances of that class or superclass). For +a mutable Parameter value, the default of False is also appropriate +if you want all instances to share the same value state, e.g. if +they are each simply referring to a single global object like +a singleton. If instead each Parameterized should have its own +independently mutable value, instantiate should be set to +True, but note that there is then no simple way to change the +value of this Parameter at the class or superclass level, +because each instance, once created, will then have an +independently instantiated value.

+

constant: if true, the Parameter value can be changed only at +the class level or in a Parameterized constructor call. The +value is otherwise constant on the Parameterized instance, +once it has been constructed.

+

readonly: if true, the Parameter value cannot ordinarily be +changed by setting the attribute at the class or instance +levels at all. The value can still be changed in code by +temporarily overriding the value of this slot and then +restoring it, which is useful for reporting values that the +_user_ should never change but which do change during code +execution.

+

pickle_default_value: whether the default value should be +pickled. Usually, you would want the default value to be pickled, +but there are rare cases where that would not be the case (e.g. +for file search paths that are specific to a certain system).

+

per_instance: whether a separate Parameter instance will be +created for every Parameterized instance. True by default. +If False, all instances of a Parameterized class will share +the same Parameter object, including all validation +attributes (bounds, etc.). See also instantiate, which is +conceptually similar but affects the Parameter value rather +than the Parameter object.

+

allow_None: if True, None is accepted as a valid value for +this Parameter, in addition to any other values that are +allowed. If the default value is defined as None, allow_None +is set to True automatically.

+

allow_refs: if True allows automatically linking parameter +references to this Parameter, i.e. the parameter value will +automatically reflect the current value of the reference that +is passed in.

+

nested_refs: if True and allow_refs=True then even nested objects +such as dictionaries, lists, slices, tuples and sets will be +inspected for references and will be automatically resolved.

+

default, doc, and precedence all default to None, which allows +inheritance of Parameter slots (attributes) from the owning-class’ +class hierarchy (see ParameterizedMetaclass).

+
+ +

Methods

+ + + + + + + + + + + + + + + + + + +

__init__([default, rows, columns, ordered, ...])

Initialize a new Parameter object and store the supplied attributes:

deserialize(value)

Given a serializable Python value, return a value that the parameter can be set to

get_range()

Return the possible types for this parameter's value.

schema([safe, subset, mode])

serialize(value)

Given the parameter value, return a Python value suitable for serialization

+

Attributes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

rows

columns

ordered

allow_None

allow_refs

class_

constant

default

doc

instantiate

is_instance

label

name

nested_refs

owner

per_instance

pickle_default_value

precedence

readonly

rx

watchers

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.DateRange.html b/reference/param/generated/param.DateRange.html new file mode 100644 index 0000000..82e35aa --- /dev/null +++ b/reference/param/generated/param.DateRange.html @@ -0,0 +1,816 @@ + + + + + + + + + + + + param.DateRange — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.DateRange#

+
+
+class param.DateRange(default=None, *, bounds=None, softbounds=None, inclusive_bounds=(True, True), step=None, length=None, doc=None, label=None, precedence=None, instantiate=False, constant=False, readonly=False, pickle_default_value=True, allow_None=False, per_instance=True, allow_refs=False, nested_refs=False)[source]#
+

A datetime or date range specified as (start, end).

+

Bounds must be specified as datetime or date types (see param.dt_types).

+
+
+__init__(default=<Undefined>, *, bounds=<Undefined>, softbounds=<Undefined>, inclusive_bounds=<Undefined>, step=<Undefined>, **params)#
+

Initialize a tuple parameter with a fixed length (number of +elements). The length is determined by the initial default +value, if any, and must be supplied explicitly otherwise. The +length is not allowed to change after instantiation.

+
+ +

Methods

+ + + + + + + + + + + + + + + + + + + + + +

__init__([default, bounds, softbounds, ...])

Initialize a tuple parameter with a fixed length (number of elements).

deserialize(value)

Given a serializable Python value, return a value that the parameter can be set to

get_soft_bounds()

rangestr()

schema([safe, subset, mode])

serialize(value)

Given the parameter value, return a Python value suitable for serialization

+

Attributes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

allow_None

allow_refs

bounds

constant

default

doc

inclusive_bounds

instantiate

label

length

name

nested_refs

owner

per_instance

pickle_default_value

precedence

readonly

rx

softbounds

step

watchers

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.Dict.html b/reference/param/generated/param.Dict.html new file mode 100644 index 0000000..66945d1 --- /dev/null +++ b/reference/param/generated/param.Dict.html @@ -0,0 +1,864 @@ + + + + + + + + + + + + param.Dict — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.Dict#

+
+
+class param.Dict(default=None, *, instantiate=True, is_instance=True, doc=None, label=None, precedence=None, constant=False, readonly=False, pickle_default_value=True, allow_None=False, per_instance=True, allow_refs=False, nested_refs=False)[source]#
+

Parameter whose value is a dictionary.

+
+
+__init__(default=None, *, is_instance=True, allow_None=False, doc=None, label=None, precedence=None, instantiate=True, constant=False, readonly=False, pickle_default_value=True, per_instance=True, allow_refs=False, nested_refs=False)[source]#
+

Initialize a new Parameter object and store the supplied attributes:

+

default: the owning class’s value for the attribute represented +by this Parameter, which can be overridden in an instance.

+

doc: docstring explaining what this parameter represents.

+

label: optional text label to be used when this Parameter is +shown in a listing. If no label is supplied, the attribute name +for this parameter in the owning Parameterized object is used.

+

precedence: a numeric value, usually in the range 0.0 to 1.0, +which allows the order of Parameters in a class to be defined in +a listing or e.g. in GUI menus. A negative precedence indicates +a parameter that should be hidden in such listings.

+

instantiate: controls whether the value of this Parameter will +be deepcopied when a Parameterized object is instantiated (if +True), or if the single default value will be shared by all +Parameterized instances (if False). For an immutable Parameter +value, it is best to leave instantiate at the default of +False, so that a user can choose to change the value at the +Parameterized instance level (affecting only that instance) or +at the Parameterized class or superclass level (affecting all +existing and future instances of that class or superclass). For +a mutable Parameter value, the default of False is also appropriate +if you want all instances to share the same value state, e.g. if +they are each simply referring to a single global object like +a singleton. If instead each Parameterized should have its own +independently mutable value, instantiate should be set to +True, but note that there is then no simple way to change the +value of this Parameter at the class or superclass level, +because each instance, once created, will then have an +independently instantiated value.

+

constant: if true, the Parameter value can be changed only at +the class level or in a Parameterized constructor call. The +value is otherwise constant on the Parameterized instance, +once it has been constructed.

+

readonly: if true, the Parameter value cannot ordinarily be +changed by setting the attribute at the class or instance +levels at all. The value can still be changed in code by +temporarily overriding the value of this slot and then +restoring it, which is useful for reporting values that the +_user_ should never change but which do change during code +execution.

+

pickle_default_value: whether the default value should be +pickled. Usually, you would want the default value to be pickled, +but there are rare cases where that would not be the case (e.g. +for file search paths that are specific to a certain system).

+

per_instance: whether a separate Parameter instance will be +created for every Parameterized instance. True by default. +If False, all instances of a Parameterized class will share +the same Parameter object, including all validation +attributes (bounds, etc.). See also instantiate, which is +conceptually similar but affects the Parameter value rather +than the Parameter object.

+

allow_None: if True, None is accepted as a valid value for +this Parameter, in addition to any other values that are +allowed. If the default value is defined as None, allow_None +is set to True automatically.

+

allow_refs: if True allows automatically linking parameter +references to this Parameter, i.e. the parameter value will +automatically reflect the current value of the reference that +is passed in.

+

nested_refs: if True and allow_refs=True then even nested objects +such as dictionaries, lists, slices, tuples and sets will be +inspected for references and will be automatically resolved.

+

default, doc, and precedence all default to None, which allows +inheritance of Parameter slots (attributes) from the owning-class’ +class hierarchy (see ParameterizedMetaclass).

+
+ +

Methods

+ + + + + + + + + + + + + + + + + + +

__init__([default, is_instance, allow_None, ...])

Initialize a new Parameter object and store the supplied attributes:

deserialize(value)

Given a serializable Python value, return a value that the parameter can be set to

get_range()

Return the possible types for this parameter's value.

schema([safe, subset, mode])

serialize(value)

Given the parameter value, return a Python value suitable for serialization

+

Attributes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

allow_None

allow_refs

class_

constant

default

doc

instantiate

is_instance

label

name

nested_refs

owner

per_instance

pickle_default_value

precedence

readonly

rx

watchers

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.Dynamic.html b/reference/param/generated/param.Dynamic.html new file mode 100644 index 0000000..48f7b41 --- /dev/null +++ b/reference/param/generated/param.Dynamic.html @@ -0,0 +1,814 @@ + + + + + + + + + + + + param.Dynamic — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.Dynamic#

+
+
+class param.Dynamic(default=None, *, doc=None, label=None, precedence=None, instantiate=False, constant=False, readonly=False, pickle_default_value=True, allow_None=False, per_instance=True, allow_refs=False, nested_refs=False)[source]#
+

Parameter whose value can be generated dynamically by a callable +object.

+

If a Parameter is declared as Dynamic, it can be set a callable +object (such as a function or callable class), and getting the +parameter’s value will call that callable.

+

Note that at present, the callable object must allow attributes +to be set on itself.

+

If set as time_dependent, setting the Dynamic.time_fn allows the +production of dynamic values to be controlled: a new value will be +produced only if the current value of time_fn is different from +what it was the last time the parameter value was requested.

+

By default, the Dynamic parameters are not time_dependent so that +new values are generated on every call regardless of the time. The +default time_fn used when time_dependent is a single Time instance +that allows general manipulations of time. It may be set to some +other callable as required so long as a number is returned on each +call.

+
+
+__init__(default=None, *, doc=None, label=None, precedence=None, instantiate=False, constant=False, readonly=False, pickle_default_value=True, allow_None=False, per_instance=True, allow_refs=False, nested_refs=False)[source]#
+

Call the superclass’s __init__ and set instantiate=True if the +default is dynamic.

+
+ +

Methods

+ + + + + + + + + + + + + + + +

__init__([default, doc, label, precedence, ...])

Call the superclass's __init__ and set instantiate=True if the default is dynamic.

deserialize(value)

Given a serializable Python value, return a value that the parameter can be set to

schema([safe, subset, mode])

serialize(value)

Given the parameter value, return a Python value suitable for serialization

+

Attributes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

allow_None

allow_refs

constant

default

doc

instantiate

label

name

nested_refs

owner

per_instance

pickle_default_value

precedence

readonly

rx

time_dependent

time_fn

watchers

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.Event.html b/reference/param/generated/param.Event.html new file mode 100644 index 0000000..6d09bba --- /dev/null +++ b/reference/param/generated/param.Event.html @@ -0,0 +1,866 @@ + + + + + + + + + + + + param.Event — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.Event#

+
+
+class param.Event(default=False, *, doc=None, label=None, precedence=None, instantiate=False, constant=False, readonly=False, pickle_default_value=True, allow_None=False, per_instance=True, allow_refs=False, nested_refs=False)[source]#
+

An Event Parameter is one whose value is intimately linked to the +triggering of events for watchers to consume. Event has a Boolean +value, which when set to True triggers the associated watchers (as +any Parameter does) and then is automatically set back to +False. Conversely, if events are triggered directly via .trigger, +the value is transiently set to True (so that it’s clear which of +many parameters being watched may have changed), then restored to +False when the triggering completes. An Event parameter is thus like +a momentary switch or pushbutton with a transient True value that +serves only to launch some other action (e.g. via a param.depends +decorator), rather than encapsulating the action itself as +param.Action does.

+
+
+__init__(default=False, *, allow_None=False, doc=None, label=None, precedence=None, instantiate=False, constant=False, readonly=False, pickle_default_value=True, per_instance=True, allow_refs=False, nested_refs=False)[source]#
+

Initialize a new Parameter object and store the supplied attributes:

+

default: the owning class’s value for the attribute represented +by this Parameter, which can be overridden in an instance.

+

doc: docstring explaining what this parameter represents.

+

label: optional text label to be used when this Parameter is +shown in a listing. If no label is supplied, the attribute name +for this parameter in the owning Parameterized object is used.

+

precedence: a numeric value, usually in the range 0.0 to 1.0, +which allows the order of Parameters in a class to be defined in +a listing or e.g. in GUI menus. A negative precedence indicates +a parameter that should be hidden in such listings.

+

instantiate: controls whether the value of this Parameter will +be deepcopied when a Parameterized object is instantiated (if +True), or if the single default value will be shared by all +Parameterized instances (if False). For an immutable Parameter +value, it is best to leave instantiate at the default of +False, so that a user can choose to change the value at the +Parameterized instance level (affecting only that instance) or +at the Parameterized class or superclass level (affecting all +existing and future instances of that class or superclass). For +a mutable Parameter value, the default of False is also appropriate +if you want all instances to share the same value state, e.g. if +they are each simply referring to a single global object like +a singleton. If instead each Parameterized should have its own +independently mutable value, instantiate should be set to +True, but note that there is then no simple way to change the +value of this Parameter at the class or superclass level, +because each instance, once created, will then have an +independently instantiated value.

+

constant: if true, the Parameter value can be changed only at +the class level or in a Parameterized constructor call. The +value is otherwise constant on the Parameterized instance, +once it has been constructed.

+

readonly: if true, the Parameter value cannot ordinarily be +changed by setting the attribute at the class or instance +levels at all. The value can still be changed in code by +temporarily overriding the value of this slot and then +restoring it, which is useful for reporting values that the +_user_ should never change but which do change during code +execution.

+

pickle_default_value: whether the default value should be +pickled. Usually, you would want the default value to be pickled, +but there are rare cases where that would not be the case (e.g. +for file search paths that are specific to a certain system).

+

per_instance: whether a separate Parameter instance will be +created for every Parameterized instance. True by default. +If False, all instances of a Parameterized class will share +the same Parameter object, including all validation +attributes (bounds, etc.). See also instantiate, which is +conceptually similar but affects the Parameter value rather +than the Parameter object.

+

allow_None: if True, None is accepted as a valid value for +this Parameter, in addition to any other values that are +allowed. If the default value is defined as None, allow_None +is set to True automatically.

+

allow_refs: if True allows automatically linking parameter +references to this Parameter, i.e. the parameter value will +automatically reflect the current value of the reference that +is passed in.

+

nested_refs: if True and allow_refs=True then even nested objects +such as dictionaries, lists, slices, tuples and sets will be +inspected for references and will be automatically resolved.

+

default, doc, and precedence all default to None, which allows +inheritance of Parameter slots (attributes) from the owning-class’ +class hierarchy (see ParameterizedMetaclass).

+
+ +

Methods

+ + + + + + + + + + + + + + + +

__init__([default, allow_None, doc, label, ...])

Initialize a new Parameter object and store the supplied attributes:

deserialize(value)

Given a serializable Python value, return a value that the parameter can be set to

schema([safe, subset, mode])

serialize(value)

Given the parameter value, return a Python value suitable for serialization

+

Attributes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

allow_None

allow_refs

constant

default

doc

instantiate

label

name

nested_refs

owner

per_instance

pickle_default_value

precedence

readonly

rx

watchers

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.FileSelector.html b/reference/param/generated/param.FileSelector.html new file mode 100644 index 0000000..55d5ddf --- /dev/null +++ b/reference/param/generated/param.FileSelector.html @@ -0,0 +1,879 @@ + + + + + + + + + + + + param.FileSelector — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.FileSelector#

+
+
+class param.FileSelector(default=None, *, path='', objects=[], instantiate=False, compute_default_fn=None, check_on_set=None, allow_None=None, empty_default=False, doc=None, label=None, precedence=None, constant=False, readonly=False, pickle_default_value=True, per_instance=True, allow_refs=False, nested_refs=False)[source]#
+

Given a path glob, allows one file to be selected from those matching.

+
+
+__init__(default=None, *, path='', objects=[], instantiate=False, compute_default_fn=None, check_on_set=None, allow_None=None, empty_default=False, doc=None, label=None, precedence=None, constant=False, readonly=False, pickle_default_value=True, per_instance=True, allow_refs=False, nested_refs=False)[source]#
+

Initialize a new Parameter object and store the supplied attributes:

+

default: the owning class’s value for the attribute represented +by this Parameter, which can be overridden in an instance.

+

doc: docstring explaining what this parameter represents.

+

label: optional text label to be used when this Parameter is +shown in a listing. If no label is supplied, the attribute name +for this parameter in the owning Parameterized object is used.

+

precedence: a numeric value, usually in the range 0.0 to 1.0, +which allows the order of Parameters in a class to be defined in +a listing or e.g. in GUI menus. A negative precedence indicates +a parameter that should be hidden in such listings.

+

instantiate: controls whether the value of this Parameter will +be deepcopied when a Parameterized object is instantiated (if +True), or if the single default value will be shared by all +Parameterized instances (if False). For an immutable Parameter +value, it is best to leave instantiate at the default of +False, so that a user can choose to change the value at the +Parameterized instance level (affecting only that instance) or +at the Parameterized class or superclass level (affecting all +existing and future instances of that class or superclass). For +a mutable Parameter value, the default of False is also appropriate +if you want all instances to share the same value state, e.g. if +they are each simply referring to a single global object like +a singleton. If instead each Parameterized should have its own +independently mutable value, instantiate should be set to +True, but note that there is then no simple way to change the +value of this Parameter at the class or superclass level, +because each instance, once created, will then have an +independently instantiated value.

+

constant: if true, the Parameter value can be changed only at +the class level or in a Parameterized constructor call. The +value is otherwise constant on the Parameterized instance, +once it has been constructed.

+

readonly: if true, the Parameter value cannot ordinarily be +changed by setting the attribute at the class or instance +levels at all. The value can still be changed in code by +temporarily overriding the value of this slot and then +restoring it, which is useful for reporting values that the +_user_ should never change but which do change during code +execution.

+

pickle_default_value: whether the default value should be +pickled. Usually, you would want the default value to be pickled, +but there are rare cases where that would not be the case (e.g. +for file search paths that are specific to a certain system).

+

per_instance: whether a separate Parameter instance will be +created for every Parameterized instance. True by default. +If False, all instances of a Parameterized class will share +the same Parameter object, including all validation +attributes (bounds, etc.). See also instantiate, which is +conceptually similar but affects the Parameter value rather +than the Parameter object.

+

allow_None: if True, None is accepted as a valid value for +this Parameter, in addition to any other values that are +allowed. If the default value is defined as None, allow_None +is set to True automatically.

+

allow_refs: if True allows automatically linking parameter +references to this Parameter, i.e. the parameter value will +automatically reflect the current value of the reference that +is passed in.

+

nested_refs: if True and allow_refs=True then even nested objects +such as dictionaries, lists, slices, tuples and sets will be +inspected for references and will be automatically resolved.

+

default, doc, and precedence all default to None, which allows +inheritance of Parameter slots (attributes) from the owning-class’ +class hierarchy (see ParameterizedMetaclass).

+
+ +

Methods

+ + + + + + + + + + + + + + + + + + + + + + + + +

__init__([default, path, objects, ...])

Initialize a new Parameter object and store the supplied attributes:

compute_default()

If this parameter's compute_default_fn is callable, call it and store the result in self.default.

deserialize(value)

Given a serializable Python value, return a value that the parameter can be set to

get_range()

Return the possible objects to which this parameter could be set.

schema([safe, subset, mode])

serialize(value)

Given the parameter value, return a Python value suitable for serialization

update([path])

+

Attributes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

path

allow_None

allow_refs

check_on_set

compute_default_fn

constant

default

doc

instantiate

label

name

names

nested_refs

objects

owner

per_instance

pickle_default_value

precedence

readonly

rx

watchers

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.Filename.html b/reference/param/generated/param.Filename.html new file mode 100644 index 0000000..2c44e1a --- /dev/null +++ b/reference/param/generated/param.Filename.html @@ -0,0 +1,873 @@ + + + + + + + + + + + + param.Filename — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.Filename#

+
+
+class param.Filename(self, default=<Undefined>, *, search_paths=<Undefined>, check_exists=<Undefined>, **params)[source]#
+

Parameter that can be set to a string specifying the path of a file.

+

The string should be specified in UNIX style, but it will be +returned in the format of the user’s operating system.

+

The specified path can be absolute, or relative to either:

+
    +
  • any of the paths specified in the search_paths attribute (if +search_paths is not None);

  • +
+

or

+
    +
  • any of the paths searched by resolve_path() (if search_paths +is None).

  • +
+
+
+__init__(default=<Undefined>, *, search_paths=<Undefined>, check_exists=<Undefined>, **params)#
+

Initialize a new Parameter object and store the supplied attributes:

+

default: the owning class’s value for the attribute represented +by this Parameter, which can be overridden in an instance.

+

doc: docstring explaining what this parameter represents.

+

label: optional text label to be used when this Parameter is +shown in a listing. If no label is supplied, the attribute name +for this parameter in the owning Parameterized object is used.

+

precedence: a numeric value, usually in the range 0.0 to 1.0, +which allows the order of Parameters in a class to be defined in +a listing or e.g. in GUI menus. A negative precedence indicates +a parameter that should be hidden in such listings.

+

instantiate: controls whether the value of this Parameter will +be deepcopied when a Parameterized object is instantiated (if +True), or if the single default value will be shared by all +Parameterized instances (if False). For an immutable Parameter +value, it is best to leave instantiate at the default of +False, so that a user can choose to change the value at the +Parameterized instance level (affecting only that instance) or +at the Parameterized class or superclass level (affecting all +existing and future instances of that class or superclass). For +a mutable Parameter value, the default of False is also appropriate +if you want all instances to share the same value state, e.g. if +they are each simply referring to a single global object like +a singleton. If instead each Parameterized should have its own +independently mutable value, instantiate should be set to +True, but note that there is then no simple way to change the +value of this Parameter at the class or superclass level, +because each instance, once created, will then have an +independently instantiated value.

+

constant: if true, the Parameter value can be changed only at +the class level or in a Parameterized constructor call. The +value is otherwise constant on the Parameterized instance, +once it has been constructed.

+

readonly: if true, the Parameter value cannot ordinarily be +changed by setting the attribute at the class or instance +levels at all. The value can still be changed in code by +temporarily overriding the value of this slot and then +restoring it, which is useful for reporting values that the +_user_ should never change but which do change during code +execution.

+

pickle_default_value: whether the default value should be +pickled. Usually, you would want the default value to be pickled, +but there are rare cases where that would not be the case (e.g. +for file search paths that are specific to a certain system).

+

per_instance: whether a separate Parameter instance will be +created for every Parameterized instance. True by default. +If False, all instances of a Parameterized class will share +the same Parameter object, including all validation +attributes (bounds, etc.). See also instantiate, which is +conceptually similar but affects the Parameter value rather +than the Parameter object.

+

allow_None: if True, None is accepted as a valid value for +this Parameter, in addition to any other values that are +allowed. If the default value is defined as None, allow_None +is set to True automatically.

+

allow_refs: if True allows automatically linking parameter +references to this Parameter, i.e. the parameter value will +automatically reflect the current value of the reference that +is passed in.

+

nested_refs: if True and allow_refs=True then even nested objects +such as dictionaries, lists, slices, tuples and sets will be +inspected for references and will be automatically resolved.

+

default, doc, and precedence all default to None, which allows +inheritance of Parameter slots (attributes) from the owning-class’ +class hierarchy (see ParameterizedMetaclass).

+
+ +

Methods

+ + + + + + + + + + + + + + + +

__init__([default, search_paths, check_exists])

Initialize a new Parameter object and store the supplied attributes:

deserialize(value)

Given a serializable Python value, return a value that the parameter can be set to

schema([safe, subset, mode])

serialize(value)

Given the parameter value, return a Python value suitable for serialization

+

Attributes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

allow_None

allow_refs

check_exists

constant

default

doc

instantiate

label

name

nested_refs

owner

per_instance

pickle_default_value

precedence

readonly

rx

search_paths

watchers

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.Foldername.html b/reference/param/generated/param.Foldername.html new file mode 100644 index 0000000..cab7e16 --- /dev/null +++ b/reference/param/generated/param.Foldername.html @@ -0,0 +1,873 @@ + + + + + + + + + + + + param.Foldername — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.Foldername#

+
+
+class param.Foldername(self, default=<Undefined>, *, search_paths=<Undefined>, check_exists=<Undefined>, **params)[source]#
+

Parameter that can be set to a string specifying the path of a folder.

+

The string should be specified in UNIX style, but it will be +returned in the format of the user’s operating system.

+

The specified path can be absolute, or relative to either:

+
    +
  • any of the paths specified in the search_paths attribute (if +search_paths is not None);

  • +
+

or

+
    +
  • any of the paths searched by resolve_dir_path() (if search_paths +is None).

  • +
+
+
+__init__(default=<Undefined>, *, search_paths=<Undefined>, check_exists=<Undefined>, **params)#
+

Initialize a new Parameter object and store the supplied attributes:

+

default: the owning class’s value for the attribute represented +by this Parameter, which can be overridden in an instance.

+

doc: docstring explaining what this parameter represents.

+

label: optional text label to be used when this Parameter is +shown in a listing. If no label is supplied, the attribute name +for this parameter in the owning Parameterized object is used.

+

precedence: a numeric value, usually in the range 0.0 to 1.0, +which allows the order of Parameters in a class to be defined in +a listing or e.g. in GUI menus. A negative precedence indicates +a parameter that should be hidden in such listings.

+

instantiate: controls whether the value of this Parameter will +be deepcopied when a Parameterized object is instantiated (if +True), or if the single default value will be shared by all +Parameterized instances (if False). For an immutable Parameter +value, it is best to leave instantiate at the default of +False, so that a user can choose to change the value at the +Parameterized instance level (affecting only that instance) or +at the Parameterized class or superclass level (affecting all +existing and future instances of that class or superclass). For +a mutable Parameter value, the default of False is also appropriate +if you want all instances to share the same value state, e.g. if +they are each simply referring to a single global object like +a singleton. If instead each Parameterized should have its own +independently mutable value, instantiate should be set to +True, but note that there is then no simple way to change the +value of this Parameter at the class or superclass level, +because each instance, once created, will then have an +independently instantiated value.

+

constant: if true, the Parameter value can be changed only at +the class level or in a Parameterized constructor call. The +value is otherwise constant on the Parameterized instance, +once it has been constructed.

+

readonly: if true, the Parameter value cannot ordinarily be +changed by setting the attribute at the class or instance +levels at all. The value can still be changed in code by +temporarily overriding the value of this slot and then +restoring it, which is useful for reporting values that the +_user_ should never change but which do change during code +execution.

+

pickle_default_value: whether the default value should be +pickled. Usually, you would want the default value to be pickled, +but there are rare cases where that would not be the case (e.g. +for file search paths that are specific to a certain system).

+

per_instance: whether a separate Parameter instance will be +created for every Parameterized instance. True by default. +If False, all instances of a Parameterized class will share +the same Parameter object, including all validation +attributes (bounds, etc.). See also instantiate, which is +conceptually similar but affects the Parameter value rather +than the Parameter object.

+

allow_None: if True, None is accepted as a valid value for +this Parameter, in addition to any other values that are +allowed. If the default value is defined as None, allow_None +is set to True automatically.

+

allow_refs: if True allows automatically linking parameter +references to this Parameter, i.e. the parameter value will +automatically reflect the current value of the reference that +is passed in.

+

nested_refs: if True and allow_refs=True then even nested objects +such as dictionaries, lists, slices, tuples and sets will be +inspected for references and will be automatically resolved.

+

default, doc, and precedence all default to None, which allows +inheritance of Parameter slots (attributes) from the owning-class’ +class hierarchy (see ParameterizedMetaclass).

+
+ +

Methods

+ + + + + + + + + + + + + + + +

__init__([default, search_paths, check_exists])

Initialize a new Parameter object and store the supplied attributes:

deserialize(value)

Given a serializable Python value, return a value that the parameter can be set to

schema([safe, subset, mode])

serialize(value)

Given the parameter value, return a Python value suitable for serialization

+

Attributes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

allow_None

allow_refs

check_exists

constant

default

doc

instantiate

label

name

nested_refs

owner

per_instance

pickle_default_value

precedence

readonly

rx

search_paths

watchers

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.HookList.html b/reference/param/generated/param.HookList.html new file mode 100644 index 0000000..e31468b --- /dev/null +++ b/reference/param/generated/param.HookList.html @@ -0,0 +1,867 @@ + + + + + + + + + + + + param.HookList — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.HookList#

+
+
+class param.HookList(default=[], *, class_=None, item_type=None, instantiate=True, bounds=(0, None), doc=None, label=None, precedence=None, constant=False, readonly=False, pickle_default_value=True, allow_None=False, per_instance=True, allow_refs=False, nested_refs=False)[source]#
+

Parameter whose value is a list of callable objects.

+

This type of List Parameter is typically used to provide a place +for users to register a set of commands to be called at a +specified place in some sequence of processing steps.

+
+
+__init__(default=<Undefined>, *, class_=<Undefined>, item_type=<Undefined>, instantiate=<Undefined>, bounds=<Undefined>, **params)#
+

Initialize a new Parameter object and store the supplied attributes:

+

default: the owning class’s value for the attribute represented +by this Parameter, which can be overridden in an instance.

+

doc: docstring explaining what this parameter represents.

+

label: optional text label to be used when this Parameter is +shown in a listing. If no label is supplied, the attribute name +for this parameter in the owning Parameterized object is used.

+

precedence: a numeric value, usually in the range 0.0 to 1.0, +which allows the order of Parameters in a class to be defined in +a listing or e.g. in GUI menus. A negative precedence indicates +a parameter that should be hidden in such listings.

+

instantiate: controls whether the value of this Parameter will +be deepcopied when a Parameterized object is instantiated (if +True), or if the single default value will be shared by all +Parameterized instances (if False). For an immutable Parameter +value, it is best to leave instantiate at the default of +False, so that a user can choose to change the value at the +Parameterized instance level (affecting only that instance) or +at the Parameterized class or superclass level (affecting all +existing and future instances of that class or superclass). For +a mutable Parameter value, the default of False is also appropriate +if you want all instances to share the same value state, e.g. if +they are each simply referring to a single global object like +a singleton. If instead each Parameterized should have its own +independently mutable value, instantiate should be set to +True, but note that there is then no simple way to change the +value of this Parameter at the class or superclass level, +because each instance, once created, will then have an +independently instantiated value.

+

constant: if true, the Parameter value can be changed only at +the class level or in a Parameterized constructor call. The +value is otherwise constant on the Parameterized instance, +once it has been constructed.

+

readonly: if true, the Parameter value cannot ordinarily be +changed by setting the attribute at the class or instance +levels at all. The value can still be changed in code by +temporarily overriding the value of this slot and then +restoring it, which is useful for reporting values that the +_user_ should never change but which do change during code +execution.

+

pickle_default_value: whether the default value should be +pickled. Usually, you would want the default value to be pickled, +but there are rare cases where that would not be the case (e.g. +for file search paths that are specific to a certain system).

+

per_instance: whether a separate Parameter instance will be +created for every Parameterized instance. True by default. +If False, all instances of a Parameterized class will share +the same Parameter object, including all validation +attributes (bounds, etc.). See also instantiate, which is +conceptually similar but affects the Parameter value rather +than the Parameter object.

+

allow_None: if True, None is accepted as a valid value for +this Parameter, in addition to any other values that are +allowed. If the default value is defined as None, allow_None +is set to True automatically.

+

allow_refs: if True allows automatically linking parameter +references to this Parameter, i.e. the parameter value will +automatically reflect the current value of the reference that +is passed in.

+

nested_refs: if True and allow_refs=True then even nested objects +such as dictionaries, lists, slices, tuples and sets will be +inspected for references and will be automatically resolved.

+

default, doc, and precedence all default to None, which allows +inheritance of Parameter slots (attributes) from the owning-class’ +class hierarchy (see ParameterizedMetaclass).

+
+ +

Methods

+ + + + + + + + + + + + + + + +

__init__([default, class_, item_type, ...])

Initialize a new Parameter object and store the supplied attributes:

deserialize(value)

Given a serializable Python value, return a value that the parameter can be set to

schema([safe, subset, mode])

serialize(value)

Given the parameter value, return a Python value suitable for serialization

+

Attributes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

class_

bounds

allow_None

allow_refs

constant

default

doc

instantiate

item_type

label

name

nested_refs

owner

per_instance

pickle_default_value

precedence

readonly

rx

watchers

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.Integer.html b/reference/param/generated/param.Integer.html new file mode 100644 index 0000000..ab2bf8e --- /dev/null +++ b/reference/param/generated/param.Integer.html @@ -0,0 +1,822 @@ + + + + + + + + + + + + param.Integer — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.Integer#

+
+
+class param.Integer(default=0, *, bounds=None, softbounds=None, inclusive_bounds=(True, True), step=None, set_hook=None, doc=None, label=None, precedence=None, instantiate=False, constant=False, readonly=False, pickle_default_value=True, allow_None=False, per_instance=True, allow_refs=False, nested_refs=False)[source]#
+

Numeric Parameter required to be an Integer

+
+
+__init__(default=<Undefined>, *, bounds=<Undefined>, softbounds=<Undefined>, inclusive_bounds=<Undefined>, step=<Undefined>, set_hook=<Undefined>, **params)#
+

Initialize this parameter object and store the bounds.

+

Non-dynamic default values are checked against the bounds.

+
+ +

Methods

+ + + + + + + + + + + + + + + + + + + + + + + + +

__init__([default, bounds, softbounds, ...])

Initialize this parameter object and store the bounds.

crop_to_bounds(val)

Return the given value cropped to be within the hard bounds for this parameter.

deserialize(value)

Given a serializable Python value, return a value that the parameter can be set to

get_soft_bounds()

schema([safe, subset, mode])

serialize(value)

Given the parameter value, return a Python value suitable for serialization

set_in_bounds(obj, val)

Set to the given value, but cropped to be within the legal bounds.

+

Attributes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

allow_None

allow_refs

bounds

constant

default

doc

inclusive_bounds

instantiate

label

name

nested_refs

owner

per_instance

pickle_default_value

precedence

readonly

rx

set_hook

softbounds

step

time_dependent

time_fn

watchers

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.List.html b/reference/param/generated/param.List.html new file mode 100644 index 0000000..a6a11dd --- /dev/null +++ b/reference/param/generated/param.List.html @@ -0,0 +1,870 @@ + + + + + + + + + + + + param.List — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.List#

+
+
+class param.List(default=[], *, class_=None, item_type=None, instantiate=True, bounds=(0, None), doc=None, label=None, precedence=None, constant=False, readonly=False, pickle_default_value=True, allow_None=False, per_instance=True, allow_refs=False, nested_refs=False)[source]#
+

Parameter whose value is a list of objects, usually of a specified type.

+

The bounds allow a minimum and/or maximum length of +list to be enforced. If the item_type is non-None, all +items in the list are checked to be of that type.

+

class_ is accepted as an alias for item_type, but is +deprecated due to conflict with how the class_ slot is +used in Selector classes.

+
+
+__init__(default=[], *, class_=None, item_type=None, instantiate=True, bounds=(0, None), allow_None=False, doc=None, label=None, precedence=None, constant=False, readonly=False, pickle_default_value=True, per_instance=True, allow_refs=False, nested_refs=False)[source]#
+

Initialize a new Parameter object and store the supplied attributes:

+

default: the owning class’s value for the attribute represented +by this Parameter, which can be overridden in an instance.

+

doc: docstring explaining what this parameter represents.

+

label: optional text label to be used when this Parameter is +shown in a listing. If no label is supplied, the attribute name +for this parameter in the owning Parameterized object is used.

+

precedence: a numeric value, usually in the range 0.0 to 1.0, +which allows the order of Parameters in a class to be defined in +a listing or e.g. in GUI menus. A negative precedence indicates +a parameter that should be hidden in such listings.

+

instantiate: controls whether the value of this Parameter will +be deepcopied when a Parameterized object is instantiated (if +True), or if the single default value will be shared by all +Parameterized instances (if False). For an immutable Parameter +value, it is best to leave instantiate at the default of +False, so that a user can choose to change the value at the +Parameterized instance level (affecting only that instance) or +at the Parameterized class or superclass level (affecting all +existing and future instances of that class or superclass). For +a mutable Parameter value, the default of False is also appropriate +if you want all instances to share the same value state, e.g. if +they are each simply referring to a single global object like +a singleton. If instead each Parameterized should have its own +independently mutable value, instantiate should be set to +True, but note that there is then no simple way to change the +value of this Parameter at the class or superclass level, +because each instance, once created, will then have an +independently instantiated value.

+

constant: if true, the Parameter value can be changed only at +the class level or in a Parameterized constructor call. The +value is otherwise constant on the Parameterized instance, +once it has been constructed.

+

readonly: if true, the Parameter value cannot ordinarily be +changed by setting the attribute at the class or instance +levels at all. The value can still be changed in code by +temporarily overriding the value of this slot and then +restoring it, which is useful for reporting values that the +_user_ should never change but which do change during code +execution.

+

pickle_default_value: whether the default value should be +pickled. Usually, you would want the default value to be pickled, +but there are rare cases where that would not be the case (e.g. +for file search paths that are specific to a certain system).

+

per_instance: whether a separate Parameter instance will be +created for every Parameterized instance. True by default. +If False, all instances of a Parameterized class will share +the same Parameter object, including all validation +attributes (bounds, etc.). See also instantiate, which is +conceptually similar but affects the Parameter value rather +than the Parameter object.

+

allow_None: if True, None is accepted as a valid value for +this Parameter, in addition to any other values that are +allowed. If the default value is defined as None, allow_None +is set to True automatically.

+

allow_refs: if True allows automatically linking parameter +references to this Parameter, i.e. the parameter value will +automatically reflect the current value of the reference that +is passed in.

+

nested_refs: if True and allow_refs=True then even nested objects +such as dictionaries, lists, slices, tuples and sets will be +inspected for references and will be automatically resolved.

+

default, doc, and precedence all default to None, which allows +inheritance of Parameter slots (attributes) from the owning-class’ +class hierarchy (see ParameterizedMetaclass).

+
+ +

Methods

+ + + + + + + + + + + + + + + +

__init__([default, class_, item_type, ...])

Initialize a new Parameter object and store the supplied attributes:

deserialize(value)

Given a serializable Python value, return a value that the parameter can be set to

schema([safe, subset, mode])

serialize(value)

Given the parameter value, return a Python value suitable for serialization

+

Attributes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

bounds

item_type

class_

allow_None

allow_refs

constant

default

doc

instantiate

label

name

nested_refs

owner

per_instance

pickle_default_value

precedence

readonly

rx

watchers

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.ListSelector.html b/reference/param/generated/param.ListSelector.html new file mode 100644 index 0000000..e2d150f --- /dev/null +++ b/reference/param/generated/param.ListSelector.html @@ -0,0 +1,874 @@ + + + + + + + + + + + + param.ListSelector — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.ListSelector#

+
+
+class param.ListSelector(default=None, *, objects=[], instantiate=False, compute_default_fn=None, check_on_set=None, allow_None=None, empty_default=False, doc=None, label=None, precedence=None, constant=False, readonly=False, pickle_default_value=True, per_instance=True, allow_refs=False, nested_refs=False)[source]#
+

Variant of Selector where the value can be multiple objects from +a list of possible objects.

+
+
+__init__(default=None, *, objects=[], instantiate=False, compute_default_fn=None, check_on_set=None, allow_None=None, empty_default=False, doc=None, label=None, precedence=None, constant=False, readonly=False, pickle_default_value=True, per_instance=True, allow_refs=False, nested_refs=False)[source]#
+

Initialize a new Parameter object and store the supplied attributes:

+

default: the owning class’s value for the attribute represented +by this Parameter, which can be overridden in an instance.

+

doc: docstring explaining what this parameter represents.

+

label: optional text label to be used when this Parameter is +shown in a listing. If no label is supplied, the attribute name +for this parameter in the owning Parameterized object is used.

+

precedence: a numeric value, usually in the range 0.0 to 1.0, +which allows the order of Parameters in a class to be defined in +a listing or e.g. in GUI menus. A negative precedence indicates +a parameter that should be hidden in such listings.

+

instantiate: controls whether the value of this Parameter will +be deepcopied when a Parameterized object is instantiated (if +True), or if the single default value will be shared by all +Parameterized instances (if False). For an immutable Parameter +value, it is best to leave instantiate at the default of +False, so that a user can choose to change the value at the +Parameterized instance level (affecting only that instance) or +at the Parameterized class or superclass level (affecting all +existing and future instances of that class or superclass). For +a mutable Parameter value, the default of False is also appropriate +if you want all instances to share the same value state, e.g. if +they are each simply referring to a single global object like +a singleton. If instead each Parameterized should have its own +independently mutable value, instantiate should be set to +True, but note that there is then no simple way to change the +value of this Parameter at the class or superclass level, +because each instance, once created, will then have an +independently instantiated value.

+

constant: if true, the Parameter value can be changed only at +the class level or in a Parameterized constructor call. The +value is otherwise constant on the Parameterized instance, +once it has been constructed.

+

readonly: if true, the Parameter value cannot ordinarily be +changed by setting the attribute at the class or instance +levels at all. The value can still be changed in code by +temporarily overriding the value of this slot and then +restoring it, which is useful for reporting values that the +_user_ should never change but which do change during code +execution.

+

pickle_default_value: whether the default value should be +pickled. Usually, you would want the default value to be pickled, +but there are rare cases where that would not be the case (e.g. +for file search paths that are specific to a certain system).

+

per_instance: whether a separate Parameter instance will be +created for every Parameterized instance. True by default. +If False, all instances of a Parameterized class will share +the same Parameter object, including all validation +attributes (bounds, etc.). See also instantiate, which is +conceptually similar but affects the Parameter value rather +than the Parameter object.

+

allow_None: if True, None is accepted as a valid value for +this Parameter, in addition to any other values that are +allowed. If the default value is defined as None, allow_None +is set to True automatically.

+

allow_refs: if True allows automatically linking parameter +references to this Parameter, i.e. the parameter value will +automatically reflect the current value of the reference that +is passed in.

+

nested_refs: if True and allow_refs=True then even nested objects +such as dictionaries, lists, slices, tuples and sets will be +inspected for references and will be automatically resolved.

+

default, doc, and precedence all default to None, which allows +inheritance of Parameter slots (attributes) from the owning-class’ +class hierarchy (see ParameterizedMetaclass).

+
+ +

Methods

+ + + + + + + + + + + + + + + + + + + + + +

__init__([default, objects, instantiate, ...])

Initialize a new Parameter object and store the supplied attributes:

compute_default()

If this parameter's compute_default_fn is callable, call it and store the result in self.default.

deserialize(value)

Given a serializable Python value, return a value that the parameter can be set to

get_range()

Return the possible objects to which this parameter could be set.

schema([safe, subset, mode])

serialize(value)

Given the parameter value, return a Python value suitable for serialization

+

Attributes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

allow_None

allow_refs

check_on_set

compute_default_fn

constant

default

doc

instantiate

label

name

names

nested_refs

objects

owner

per_instance

pickle_default_value

precedence

readonly

rx

watchers

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.Magnitude.html b/reference/param/generated/param.Magnitude.html new file mode 100644 index 0000000..6c12996 --- /dev/null +++ b/reference/param/generated/param.Magnitude.html @@ -0,0 +1,822 @@ + + + + + + + + + + + + param.Magnitude — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.Magnitude#

+
+
+class param.Magnitude(default=1.0, *, bounds=(0.0, 1.0), softbounds=None, inclusive_bounds=(True, True), step=None, set_hook=None, doc=None, label=None, precedence=None, instantiate=False, constant=False, readonly=False, pickle_default_value=True, allow_None=False, per_instance=True, allow_refs=False, nested_refs=False)[source]#
+

Numeric Parameter required to be in the range [0.0-1.0].

+
+
+__init__(default=1.0, *, bounds=(0.0, 1.0), softbounds=None, inclusive_bounds=(True, True), step=None, set_hook=None, allow_None=False, doc=None, label=None, precedence=None, instantiate=False, constant=False, readonly=False, pickle_default_value=True, per_instance=True, allow_refs=False, nested_refs=False)[source]#
+

Initialize this parameter object and store the bounds.

+

Non-dynamic default values are checked against the bounds.

+
+ +

Methods

+ + + + + + + + + + + + + + + + + + + + + + + + +

__init__([default, bounds, softbounds, ...])

Initialize this parameter object and store the bounds.

crop_to_bounds(val)

Return the given value cropped to be within the hard bounds for this parameter.

deserialize(value)

Given a serializable Python value, return a value that the parameter can be set to

get_soft_bounds()

schema([safe, subset, mode])

serialize(value)

Given the parameter value, return a Python value suitable for serialization

set_in_bounds(obj, val)

Set to the given value, but cropped to be within the legal bounds.

+

Attributes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

allow_None

allow_refs

bounds

constant

default

doc

inclusive_bounds

instantiate

label

name

nested_refs

owner

per_instance

pickle_default_value

precedence

readonly

rx

set_hook

softbounds

step

time_dependent

time_fn

watchers

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.MultiFileSelector.html b/reference/param/generated/param.MultiFileSelector.html new file mode 100644 index 0000000..7c939c7 --- /dev/null +++ b/reference/param/generated/param.MultiFileSelector.html @@ -0,0 +1,879 @@ + + + + + + + + + + + + param.MultiFileSelector — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.MultiFileSelector#

+
+
+class param.MultiFileSelector(default=None, *, path='', objects=[], instantiate=False, compute_default_fn=None, check_on_set=None, allow_None=None, empty_default=False, doc=None, label=None, precedence=None, constant=False, readonly=False, pickle_default_value=True, per_instance=True, allow_refs=False, nested_refs=False)[source]#
+

Given a path glob, allows multiple files to be selected from the list of matches.

+
+
+__init__(default=None, *, path='', objects=[], compute_default_fn=None, check_on_set=None, allow_None=None, empty_default=False, doc=None, label=None, precedence=None, instantiate=False, constant=False, readonly=False, pickle_default_value=True, per_instance=True, allow_refs=False, nested_refs=False)[source]#
+

Initialize a new Parameter object and store the supplied attributes:

+

default: the owning class’s value for the attribute represented +by this Parameter, which can be overridden in an instance.

+

doc: docstring explaining what this parameter represents.

+

label: optional text label to be used when this Parameter is +shown in a listing. If no label is supplied, the attribute name +for this parameter in the owning Parameterized object is used.

+

precedence: a numeric value, usually in the range 0.0 to 1.0, +which allows the order of Parameters in a class to be defined in +a listing or e.g. in GUI menus. A negative precedence indicates +a parameter that should be hidden in such listings.

+

instantiate: controls whether the value of this Parameter will +be deepcopied when a Parameterized object is instantiated (if +True), or if the single default value will be shared by all +Parameterized instances (if False). For an immutable Parameter +value, it is best to leave instantiate at the default of +False, so that a user can choose to change the value at the +Parameterized instance level (affecting only that instance) or +at the Parameterized class or superclass level (affecting all +existing and future instances of that class or superclass). For +a mutable Parameter value, the default of False is also appropriate +if you want all instances to share the same value state, e.g. if +they are each simply referring to a single global object like +a singleton. If instead each Parameterized should have its own +independently mutable value, instantiate should be set to +True, but note that there is then no simple way to change the +value of this Parameter at the class or superclass level, +because each instance, once created, will then have an +independently instantiated value.

+

constant: if true, the Parameter value can be changed only at +the class level or in a Parameterized constructor call. The +value is otherwise constant on the Parameterized instance, +once it has been constructed.

+

readonly: if true, the Parameter value cannot ordinarily be +changed by setting the attribute at the class or instance +levels at all. The value can still be changed in code by +temporarily overriding the value of this slot and then +restoring it, which is useful for reporting values that the +_user_ should never change but which do change during code +execution.

+

pickle_default_value: whether the default value should be +pickled. Usually, you would want the default value to be pickled, +but there are rare cases where that would not be the case (e.g. +for file search paths that are specific to a certain system).

+

per_instance: whether a separate Parameter instance will be +created for every Parameterized instance. True by default. +If False, all instances of a Parameterized class will share +the same Parameter object, including all validation +attributes (bounds, etc.). See also instantiate, which is +conceptually similar but affects the Parameter value rather +than the Parameter object.

+

allow_None: if True, None is accepted as a valid value for +this Parameter, in addition to any other values that are +allowed. If the default value is defined as None, allow_None +is set to True automatically.

+

allow_refs: if True allows automatically linking parameter +references to this Parameter, i.e. the parameter value will +automatically reflect the current value of the reference that +is passed in.

+

nested_refs: if True and allow_refs=True then even nested objects +such as dictionaries, lists, slices, tuples and sets will be +inspected for references and will be automatically resolved.

+

default, doc, and precedence all default to None, which allows +inheritance of Parameter slots (attributes) from the owning-class’ +class hierarchy (see ParameterizedMetaclass).

+
+ +

Methods

+ + + + + + + + + + + + + + + + + + + + + + + + +

__init__([default, path, objects, ...])

Initialize a new Parameter object and store the supplied attributes:

compute_default()

If this parameter's compute_default_fn is callable, call it and store the result in self.default.

deserialize(value)

Given a serializable Python value, return a value that the parameter can be set to

get_range()

Return the possible objects to which this parameter could be set.

schema([safe, subset, mode])

serialize(value)

Given the parameter value, return a Python value suitable for serialization

update([path])

+

Attributes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

path

allow_None

allow_refs

check_on_set

compute_default_fn

constant

default

doc

instantiate

label

name

names

nested_refs

objects

owner

per_instance

pickle_default_value

precedence

readonly

rx

watchers

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.Number.html b/reference/param/generated/param.Number.html new file mode 100644 index 0000000..817a691 --- /dev/null +++ b/reference/param/generated/param.Number.html @@ -0,0 +1,855 @@ + + + + + + + + + + + + param.Number — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.Number#

+
+
+class param.Number(default=0.0, *, bounds=None, softbounds=None, inclusive_bounds=(True, True), step=None, set_hook=None, doc=None, label=None, precedence=None, instantiate=False, constant=False, readonly=False, pickle_default_value=True, allow_None=False, per_instance=True, allow_refs=False, nested_refs=False)[source]#
+

A numeric Dynamic Parameter, with a default value and optional bounds.

+

There are two types of bounds: bounds and +softbounds. bounds are hard bounds: the parameter must +have a value within the specified range. The default bounds are +(None,None), meaning there are actually no hard bounds. One or +both bounds can be set by specifying a value +(e.g. bounds=(None,10) means there is no lower bound, and an upper +bound of 10). Bounds are inclusive by default, but exclusivity +can be specified for each bound by setting inclusive_bounds +(e.g. inclusive_bounds=(True,False) specifies an exclusive upper +bound).

+

Number is also a type of Dynamic parameter, so its value +can be set to a callable to get a dynamically generated +number (see Dynamic).

+

When not being dynamically generated, bounds are checked when a +Number is created or set. Using a default value outside the hard +bounds, or one that is not numeric, results in an exception. When +being dynamically generated, bounds are checked when the value +of a Number is requested. A generated value that is not numeric, +or is outside the hard bounds, results in an exception.

+

As a special case, if allow_None=True (which is true by default if +the parameter has a default of None when declared) then a value +of None is also allowed.

+

A separate function set_in_bounds() is provided that will +silently crop the given value into the legal range, for use +in, for instance, a GUI.

+

softbounds are present to indicate the typical range of +the parameter, but are not enforced. Setting the soft bounds +allows, for instance, a GUI to know what values to display on +sliders for the Number.

+

Example of creating a Number:

+
AB = Number(default=0.5, bounds=(None,10), softbounds=(0,1), doc='Distance from A to B.')
+
+
+
+
+__init__(default=0.0, *, bounds=None, softbounds=None, inclusive_bounds=(True, True), step=None, set_hook=None, allow_None=False, doc=None, label=None, precedence=None, instantiate=False, constant=False, readonly=False, pickle_default_value=True, per_instance=True, allow_refs=False, nested_refs=False)[source]#
+

Initialize this parameter object and store the bounds.

+

Non-dynamic default values are checked against the bounds.

+
+ +

Methods

+ + + + + + + + + + + + + + + + + + + + + + + + +

__init__([default, bounds, softbounds, ...])

Initialize this parameter object and store the bounds.

crop_to_bounds(val)

Return the given value cropped to be within the hard bounds for this parameter.

deserialize(value)

Given a serializable Python value, return a value that the parameter can be set to

get_soft_bounds()

schema([safe, subset, mode])

serialize(value)

Given the parameter value, return a Python value suitable for serialization

set_in_bounds(obj, val)

Set to the given value, but cropped to be within the legal bounds.

+

Attributes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

bounds

softbounds

inclusive_bounds

set_hook

step

allow_None

allow_refs

constant

default

doc

instantiate

label

name

nested_refs

owner

per_instance

pickle_default_value

precedence

readonly

rx

time_dependent

time_fn

watchers

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.NumericTuple.html b/reference/param/generated/param.NumericTuple.html new file mode 100644 index 0000000..f3a6cd2 --- /dev/null +++ b/reference/param/generated/param.NumericTuple.html @@ -0,0 +1,797 @@ + + + + + + + + + + + + param.NumericTuple — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.NumericTuple#

+
+
+class param.NumericTuple(default=(0, 0), *, length=None, doc=None, label=None, precedence=None, instantiate=False, constant=False, readonly=False, pickle_default_value=True, allow_None=False, per_instance=True, allow_refs=False, nested_refs=False)[source]#
+

A numeric tuple Parameter (e.g. (4.5,7.6,3)) with a fixed tuple length.

+
+
+__init__(default=<Undefined>, *, length=<Undefined>, **params)#
+

Initialize a tuple parameter with a fixed length (number of +elements). The length is determined by the initial default +value, if any, and must be supplied explicitly otherwise. The +length is not allowed to change after instantiation.

+
+ +

Methods

+ + + + + + + + + + + + + + + +

__init__([default, length])

Initialize a tuple parameter with a fixed length (number of elements).

deserialize(value)

Given a serializable Python value, return a value that the parameter can be set to

schema([safe, subset, mode])

serialize(value)

Given the parameter value, return a Python value suitable for serialization

+

Attributes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

allow_None

allow_refs

constant

default

doc

instantiate

label

length

name

nested_refs

owner

per_instance

pickle_default_value

precedence

readonly

rx

watchers

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.ParamOverrides.html b/reference/param/generated/param.ParamOverrides.html new file mode 100644 index 0000000..2224bca --- /dev/null +++ b/reference/param/generated/param.ParamOverrides.html @@ -0,0 +1,775 @@ + + + + + + + + + + + + param.ParamOverrides — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.ParamOverrides#

+
+
+class param.ParamOverrides(overridden, dict_, allow_extra_keywords=False)[source]#
+

A dictionary that returns the attribute of a specified object if +that attribute is not present in itself.

+

Used to override the parameters of an object.

+
+
+__init__(overridden, dict_, allow_extra_keywords=False)[source]#
+

If allow_extra_keywords is False, then all keys in the +supplied dict_ must match parameter names on the overridden +object (otherwise a warning will be printed).

+

If allow_extra_keywords is True, then any items in the +supplied dict_ that are not also parameters of the overridden +object will be available via the extra_keywords() method.

+
+ +

Methods

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

__init__(overridden, dict_[, ...])

If allow_extra_keywords is False, then all keys in the supplied dict_ must match parameter names on the overridden object (otherwise a warning will be printed).

clear()

copy()

extra_keywords()

Return a dictionary containing items from the originally supplied dict_ whose names are not parameters of the overridden object.

fromkeys([value])

Create a new dictionary with keys from iterable and values set to value.

get(key[, default])

Return the value for key if key is in the dictionary, else default.

items()

keys()

param_keywords()

Return a dictionary containing items from the originally supplied dict_ whose names are parameters of the overridden object (i.e.

pop(k[,d])

If key is not found, default is returned if given, otherwise KeyError is raised

popitem()

Remove and return a (key, value) pair as a 2-tuple.

setdefault(key[, default])

Insert key with a value of default if key is not in the dictionary.

update([E, ]**F)

If E is present and has a .keys() method, then does: for k in E: D[k] = E[k] If E is present and lacks a .keys() method, then does: for k, v in E: D[k] = v In either case, this is followed by: for k in F: D[k] = F[k]

values()

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.Parameter.html b/reference/param/generated/param.Parameter.html new file mode 100644 index 0000000..7733b86 --- /dev/null +++ b/reference/param/generated/param.Parameter.html @@ -0,0 +1,924 @@ + + + + + + + + + + + + param.Parameter — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.Parameter#

+
+
+class param.Parameter(default=None, *, doc=None, label=None, precedence=None, instantiate=False, constant=False, readonly=False, pickle_default_value=True, allow_None=False, per_instance=True, allow_refs=False, nested_refs=False)[source]#
+

An attribute descriptor for declaring parameters.

+

Parameters are a special kind of class attribute. Setting a +Parameterized class attribute to be a Parameter instance causes +that attribute of the class (and the class’s instances) to be +treated as a Parameter. This allows special behavior, including +dynamically generated parameter values, documentation strings, +constant and read-only parameters, and type or range checking at +assignment time.

+

For example, suppose someone wants to define two new kinds of +objects Foo and Bar, such that Bar has a parameter delta, Foo is a +subclass of Bar, and Foo has parameters alpha, sigma, and gamma +(and delta inherited from Bar). She would begin her class +definitions with something like this:

+
class Bar(Parameterized):
+    delta = Parameter(default=0.6, doc='The difference between steps.')
+    ...
+class Foo(Bar):
+    alpha = Parameter(default=0.1, doc='The starting value.')
+    sigma = Parameter(default=0.5, doc='The standard deviation.',
+                    constant=True)
+    gamma = Parameter(default=1.0, doc='The ending value.')
+    ...
+
+
+

Class Foo would then have four parameters, with delta defaulting +to 0.6.

+

Parameters have several advantages over plain attributes:

+
    +
  1. Parameters can be set automatically when an instance is +constructed: The default constructor for Foo (and Bar) will +accept arbitrary keyword arguments, each of which can be used +to specify the value of a Parameter of Foo (or any of Foo’s +superclasses). E.g., if a script does this:

    +
    myfoo = Foo(alpha=0.5)
    +
    +
    +

    myfoo.alpha will return 0.5, without the Foo constructor +needing special code to set alpha.

    +

    If Foo implements its own constructor, keyword arguments will +still be accepted if the constructor accepts a dictionary of +keyword arguments (as in def __init__(self,**params):), and +then each class calls its superclass (as in +super(Foo,self).__init__(**params)) so that the +Parameterized constructor will process the keywords.

    +
  2. +
  3. A Parameterized class need specify only the attributes of a +Parameter whose values differ from those declared in +superclasses; the other values will be inherited. E.g. if Foo +declares:

    +
    delta = Parameter(default=0.2)
    +
    +
    +

    the default value of 0.2 will override the 0.6 inherited from +Bar, but the doc will be inherited from Bar.

    +
  4. +
  5. The Parameter descriptor class can be subclassed to provide +more complex behavior, allowing special types of parameters +that, for example, require their values to be numbers in +certain ranges, generate their values dynamically from a random +distribution, or read their values from a file or other +external source.

  6. +
  7. The attributes associated with Parameters provide enough +information for automatically generating property sheets in +graphical user interfaces, allowing Parameterized instances to +be edited by users.

  8. +
+

Note that Parameters can only be used when set as class attributes +of Parameterized classes. Parameters used as standalone objects, +or as class attributes of non-Parameterized classes, will not have +the behavior described here.

+
+
+__init__(default=None, *, doc=None, label=None, precedence=None, instantiate=False, constant=False, readonly=False, pickle_default_value=True, allow_None=False, per_instance=True, allow_refs=False, nested_refs=False)[source]#
+

Initialize a new Parameter object and store the supplied attributes:

+

default: the owning class’s value for the attribute represented +by this Parameter, which can be overridden in an instance.

+

doc: docstring explaining what this parameter represents.

+

label: optional text label to be used when this Parameter is +shown in a listing. If no label is supplied, the attribute name +for this parameter in the owning Parameterized object is used.

+

precedence: a numeric value, usually in the range 0.0 to 1.0, +which allows the order of Parameters in a class to be defined in +a listing or e.g. in GUI menus. A negative precedence indicates +a parameter that should be hidden in such listings.

+

instantiate: controls whether the value of this Parameter will +be deepcopied when a Parameterized object is instantiated (if +True), or if the single default value will be shared by all +Parameterized instances (if False). For an immutable Parameter +value, it is best to leave instantiate at the default of +False, so that a user can choose to change the value at the +Parameterized instance level (affecting only that instance) or +at the Parameterized class or superclass level (affecting all +existing and future instances of that class or superclass). For +a mutable Parameter value, the default of False is also appropriate +if you want all instances to share the same value state, e.g. if +they are each simply referring to a single global object like +a singleton. If instead each Parameterized should have its own +independently mutable value, instantiate should be set to +True, but note that there is then no simple way to change the +value of this Parameter at the class or superclass level, +because each instance, once created, will then have an +independently instantiated value.

+

constant: if true, the Parameter value can be changed only at +the class level or in a Parameterized constructor call. The +value is otherwise constant on the Parameterized instance, +once it has been constructed.

+

readonly: if true, the Parameter value cannot ordinarily be +changed by setting the attribute at the class or instance +levels at all. The value can still be changed in code by +temporarily overriding the value of this slot and then +restoring it, which is useful for reporting values that the +_user_ should never change but which do change during code +execution.

+

pickle_default_value: whether the default value should be +pickled. Usually, you would want the default value to be pickled, +but there are rare cases where that would not be the case (e.g. +for file search paths that are specific to a certain system).

+

per_instance: whether a separate Parameter instance will be +created for every Parameterized instance. True by default. +If False, all instances of a Parameterized class will share +the same Parameter object, including all validation +attributes (bounds, etc.). See also instantiate, which is +conceptually similar but affects the Parameter value rather +than the Parameter object.

+

allow_None: if True, None is accepted as a valid value for +this Parameter, in addition to any other values that are +allowed. If the default value is defined as None, allow_None +is set to True automatically.

+

allow_refs: if True allows automatically linking parameter +references to this Parameter, i.e. the parameter value will +automatically reflect the current value of the reference that +is passed in.

+

nested_refs: if True and allow_refs=True then even nested objects +such as dictionaries, lists, slices, tuples and sets will be +inspected for references and will be automatically resolved.

+

default, doc, and precedence all default to None, which allows +inheritance of Parameter slots (attributes) from the owning-class’ +class hierarchy (see ParameterizedMetaclass).

+
+ +

Methods

+ + + + + + + + + + + + + + + +

__init__([default, doc, label, precedence, ...])

Initialize a new Parameter object and store the supplied attributes:

deserialize(value)

Given a serializable Python value, return a value that the parameter can be set to

schema([safe, subset, mode])

serialize(value)

Given the parameter value, return a Python value suitable for serialization

+

Attributes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

name

default

doc

precedence

instantiate

constant

readonly

pickle_default_value

allow_None

per_instance

watchers

owner

allow_refs

nested_refs

label

rx

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.Parameterized.html b/reference/param/generated/param.Parameterized.html new file mode 100644 index 0000000..07bca14 --- /dev/null +++ b/reference/param/generated/param.Parameterized.html @@ -0,0 +1,773 @@ + + + + + + + + + + + + param.Parameterized — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.Parameterized#

+
+
+class param.Parameterized(*, name)[source]#
+

Base class for named objects that support Parameters and message +formatting.

+

Automatic object naming: Every Parameterized instance has a name +parameter. If the user doesn’t designate a name=<str> argument +when constructing the object, the object will be given a name +consisting of its class name followed by a unique 5-digit number.

+

Automatic parameter setting: The Parameterized __init__ method +will automatically read the list of keyword parameters. If any +keyword matches the name of a Parameter (see Parameter class) +defined in the object’s class or any of its superclasses, that +parameter in the instance will get the value given as a keyword +argument. For example:

+
+
+
class Foo(Parameterized):

xx = Parameter(default=1)

+
+
+

foo = Foo(xx=20)

+
+

in this case foo.xx gets the value 20.

+

When initializing a Parameterized instance (‘foo’ in the example +above), the values of parameters can be supplied as keyword +arguments to the constructor (using parametername=parametervalue); +these values will override the class default values for this one +instance.

+

If no ‘name’ parameter is supplied, self.name defaults to the +object’s class name with a unique number appended to it.

+

Message formatting: Each Parameterized instance has several +methods for optionally printing output. This functionality is +based on the standard Python ‘logging’ module; using the methods +provided here, wraps calls to the ‘logging’ module’s root logger +and prepends each message with information about the instance +from which the call was made. For more information on how to set +the global logging level and change the default message prefix, +see documentation for the ‘logging’ module.

+
+
+__init__(**params)[source]#
+
+ +

Methods

+ + + + + + +

__init__(**params)

+

Attributes

+ + + + + + + + + +

name

param

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.ParameterizedFunction.html b/reference/param/generated/param.ParameterizedFunction.html new file mode 100644 index 0000000..626015a --- /dev/null +++ b/reference/param/generated/param.ParameterizedFunction.html @@ -0,0 +1,746 @@ + + + + + + + + + + + + param.ParameterizedFunction — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.ParameterizedFunction#

+
+
+class param.ParameterizedFunction(*, name)[source]#
+

Acts like a Python function, but with arguments that are Parameters.

+

Implemented as a subclass of Parameterized that, when instantiated, +automatically invokes __call__ and returns the result, instead of +returning an instance of the class.

+

To obtain an instance of this class, call instance().

+
+
+__init__(**params)#
+
+ +

Methods

+ + + + + + + + + +

__init__(**params)

instance(**params)

Return an instance of this class, copying parameters from any existing instance provided.

+

Attributes

+ + + + + + + + + +

name

param

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.Path.html b/reference/param/generated/param.Path.html new file mode 100644 index 0000000..ca553f7 --- /dev/null +++ b/reference/param/generated/param.Path.html @@ -0,0 +1,887 @@ + + + + + + + + + + + + param.Path — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.Path#

+
+
+class param.Path(self, default=<Undefined>, *, search_paths=<Undefined>, check_exists=<Undefined>, **params)[source]#
+

Parameter that can be set to a string specifying the path of a file or folder.

+

The string should be specified in UNIX style, but it will be +returned in the format of the user’s operating system. Please use +the Filename or Foldername Parameters if you require discrimination +between the two possibilities.

+

The specified path can be absolute, or relative to either:

+
    +
  • +
    any of the paths specified in the search_paths attribute (if

    search_paths is not None);

    +
    +
    +
  • +
+

or

+
    +
  • any of the paths searched by resolve_path() (if search_paths +is None).

  • +
+
+
Parameters:
+
    +
  • search_paths (list, default=[os.getcwd()]) – List of paths to search the path from

  • +
  • check_exists (boolean, default=True) – If True (default) the path must exist on instantiation and set, +otherwise the path can optionally exist.

  • +
+
+
+
+
+__init__(default=None, *, search_paths=None, check_exists=True, allow_None=False, doc=None, label=None, precedence=None, instantiate=False, constant=False, readonly=False, pickle_default_value=True, per_instance=True, allow_refs=False, nested_refs=False)[source]#
+

Initialize a new Parameter object and store the supplied attributes:

+

default: the owning class’s value for the attribute represented +by this Parameter, which can be overridden in an instance.

+

doc: docstring explaining what this parameter represents.

+

label: optional text label to be used when this Parameter is +shown in a listing. If no label is supplied, the attribute name +for this parameter in the owning Parameterized object is used.

+

precedence: a numeric value, usually in the range 0.0 to 1.0, +which allows the order of Parameters in a class to be defined in +a listing or e.g. in GUI menus. A negative precedence indicates +a parameter that should be hidden in such listings.

+

instantiate: controls whether the value of this Parameter will +be deepcopied when a Parameterized object is instantiated (if +True), or if the single default value will be shared by all +Parameterized instances (if False). For an immutable Parameter +value, it is best to leave instantiate at the default of +False, so that a user can choose to change the value at the +Parameterized instance level (affecting only that instance) or +at the Parameterized class or superclass level (affecting all +existing and future instances of that class or superclass). For +a mutable Parameter value, the default of False is also appropriate +if you want all instances to share the same value state, e.g. if +they are each simply referring to a single global object like +a singleton. If instead each Parameterized should have its own +independently mutable value, instantiate should be set to +True, but note that there is then no simple way to change the +value of this Parameter at the class or superclass level, +because each instance, once created, will then have an +independently instantiated value.

+

constant: if true, the Parameter value can be changed only at +the class level or in a Parameterized constructor call. The +value is otherwise constant on the Parameterized instance, +once it has been constructed.

+

readonly: if true, the Parameter value cannot ordinarily be +changed by setting the attribute at the class or instance +levels at all. The value can still be changed in code by +temporarily overriding the value of this slot and then +restoring it, which is useful for reporting values that the +_user_ should never change but which do change during code +execution.

+

pickle_default_value: whether the default value should be +pickled. Usually, you would want the default value to be pickled, +but there are rare cases where that would not be the case (e.g. +for file search paths that are specific to a certain system).

+

per_instance: whether a separate Parameter instance will be +created for every Parameterized instance. True by default. +If False, all instances of a Parameterized class will share +the same Parameter object, including all validation +attributes (bounds, etc.). See also instantiate, which is +conceptually similar but affects the Parameter value rather +than the Parameter object.

+

allow_None: if True, None is accepted as a valid value for +this Parameter, in addition to any other values that are +allowed. If the default value is defined as None, allow_None +is set to True automatically.

+

allow_refs: if True allows automatically linking parameter +references to this Parameter, i.e. the parameter value will +automatically reflect the current value of the reference that +is passed in.

+

nested_refs: if True and allow_refs=True then even nested objects +such as dictionaries, lists, slices, tuples and sets will be +inspected for references and will be automatically resolved.

+

default, doc, and precedence all default to None, which allows +inheritance of Parameter slots (attributes) from the owning-class’ +class hierarchy (see ParameterizedMetaclass).

+
+ +

Methods

+ + + + + + + + + + + + + + + +

__init__([default, search_paths, ...])

Initialize a new Parameter object and store the supplied attributes:

deserialize(value)

Given a serializable Python value, return a value that the parameter can be set to

schema([safe, subset, mode])

serialize(value)

Given the parameter value, return a Python value suitable for serialization

+

Attributes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

search_paths

check_exists

allow_None

allow_refs

constant

default

doc

instantiate

label

name

nested_refs

owner

per_instance

pickle_default_value

precedence

readonly

rx

watchers

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.Range.html b/reference/param/generated/param.Range.html new file mode 100644 index 0000000..711c496 --- /dev/null +++ b/reference/param/generated/param.Range.html @@ -0,0 +1,815 @@ + + + + + + + + + + + + param.Range — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.Range#

+
+
+class param.Range(default=None, *, bounds=None, softbounds=None, inclusive_bounds=(True, True), step=None, length=None, doc=None, label=None, precedence=None, instantiate=False, constant=False, readonly=False, pickle_default_value=True, allow_None=False, per_instance=True, allow_refs=False, nested_refs=False)[source]#
+

A numeric range with optional bounds and softbounds.

+
+
+__init__(default=None, *, bounds=None, softbounds=None, inclusive_bounds=(True, True), step=None, length=None, doc=None, label=None, precedence=None, instantiate=False, constant=False, readonly=False, pickle_default_value=True, allow_None=False, per_instance=True, allow_refs=False, nested_refs=False)[source]#
+

Initialize a tuple parameter with a fixed length (number of +elements). The length is determined by the initial default +value, if any, and must be supplied explicitly otherwise. The +length is not allowed to change after instantiation.

+
+ +

Methods

+ + + + + + + + + + + + + + + + + + + + + +

__init__([default, bounds, softbounds, ...])

Initialize a tuple parameter with a fixed length (number of elements).

deserialize(value)

Given a serializable Python value, return a value that the parameter can be set to

get_soft_bounds()

rangestr()

schema([safe, subset, mode])

serialize(value)

Given the parameter value, return a Python value suitable for serialization

+

Attributes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

bounds

inclusive_bounds

softbounds

step

allow_None

allow_refs

constant

default

doc

instantiate

label

length

name

nested_refs

owner

per_instance

pickle_default_value

precedence

readonly

rx

watchers

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.Selector.html b/reference/param/generated/param.Selector.html new file mode 100644 index 0000000..89481c1 --- /dev/null +++ b/reference/param/generated/param.Selector.html @@ -0,0 +1,892 @@ + + + + + + + + + + + + param.Selector — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.Selector#

+
+
+class param.Selector(*, objects=[], default=None, instantiate=False, compute_default_fn=None, check_on_set=None, allow_None=None, empty_default=False, doc=None, label=None, precedence=None, constant=False, readonly=False, pickle_default_value=True, per_instance=True, allow_refs=False, nested_refs=False)[source]#
+

Parameter whose value must be one object from a list of possible objects.

+

By default, if no default is specified, picks the first object from +the provided set of objects, as long as the objects are in an +ordered data collection.

+

check_on_set restricts the value to be among the current list of +objects. By default, if objects are initially supplied, +check_on_set is True, whereas if no objects are initially +supplied, check_on_set is False. This can be overridden by +explicitly specifying check_on_set initially.

+

If check_on_set is True (either because objects are supplied +initially, or because it is explicitly specified), the default +(initial) value must be among the list of objects (unless the +default value is None).

+

The list of objects can be supplied as a list (appropriate for +selecting among a set of strings, or among a set of objects with a +“name” parameter), or as a (preferably ordered) dictionary from +names to objects. If a dictionary is supplied, the objects +will need to be hashable so that their names can be looked +up from the object value.

+

empty_default is an internal argument that does not have a slot.

+
+
+__init__(*, objects=[], default=None, instantiate=False, compute_default_fn=None, check_on_set=None, allow_None=None, empty_default=False, doc=None, label=None, precedence=None, constant=False, readonly=False, pickle_default_value=True, per_instance=True, allow_refs=False, nested_refs=False)[source]#
+

Initialize a new Parameter object and store the supplied attributes:

+

default: the owning class’s value for the attribute represented +by this Parameter, which can be overridden in an instance.

+

doc: docstring explaining what this parameter represents.

+

label: optional text label to be used when this Parameter is +shown in a listing. If no label is supplied, the attribute name +for this parameter in the owning Parameterized object is used.

+

precedence: a numeric value, usually in the range 0.0 to 1.0, +which allows the order of Parameters in a class to be defined in +a listing or e.g. in GUI menus. A negative precedence indicates +a parameter that should be hidden in such listings.

+

instantiate: controls whether the value of this Parameter will +be deepcopied when a Parameterized object is instantiated (if +True), or if the single default value will be shared by all +Parameterized instances (if False). For an immutable Parameter +value, it is best to leave instantiate at the default of +False, so that a user can choose to change the value at the +Parameterized instance level (affecting only that instance) or +at the Parameterized class or superclass level (affecting all +existing and future instances of that class or superclass). For +a mutable Parameter value, the default of False is also appropriate +if you want all instances to share the same value state, e.g. if +they are each simply referring to a single global object like +a singleton. If instead each Parameterized should have its own +independently mutable value, instantiate should be set to +True, but note that there is then no simple way to change the +value of this Parameter at the class or superclass level, +because each instance, once created, will then have an +independently instantiated value.

+

constant: if true, the Parameter value can be changed only at +the class level or in a Parameterized constructor call. The +value is otherwise constant on the Parameterized instance, +once it has been constructed.

+

readonly: if true, the Parameter value cannot ordinarily be +changed by setting the attribute at the class or instance +levels at all. The value can still be changed in code by +temporarily overriding the value of this slot and then +restoring it, which is useful for reporting values that the +_user_ should never change but which do change during code +execution.

+

pickle_default_value: whether the default value should be +pickled. Usually, you would want the default value to be pickled, +but there are rare cases where that would not be the case (e.g. +for file search paths that are specific to a certain system).

+

per_instance: whether a separate Parameter instance will be +created for every Parameterized instance. True by default. +If False, all instances of a Parameterized class will share +the same Parameter object, including all validation +attributes (bounds, etc.). See also instantiate, which is +conceptually similar but affects the Parameter value rather +than the Parameter object.

+

allow_None: if True, None is accepted as a valid value for +this Parameter, in addition to any other values that are +allowed. If the default value is defined as None, allow_None +is set to True automatically.

+

allow_refs: if True allows automatically linking parameter +references to this Parameter, i.e. the parameter value will +automatically reflect the current value of the reference that +is passed in.

+

nested_refs: if True and allow_refs=True then even nested objects +such as dictionaries, lists, slices, tuples and sets will be +inspected for references and will be automatically resolved.

+

default, doc, and precedence all default to None, which allows +inheritance of Parameter slots (attributes) from the owning-class’ +class hierarchy (see ParameterizedMetaclass).

+
+ +

Methods

+ + + + + + + + + + + + + + + + + + + + + +

__init__(*[, objects, default, instantiate, ...])

Initialize a new Parameter object and store the supplied attributes:

compute_default()

If this parameter's compute_default_fn is callable, call it and store the result in self.default.

deserialize(value)

Given a serializable Python value, return a value that the parameter can be set to

get_range()

Return the possible objects to which this parameter could be set.

schema([safe, subset, mode])

serialize(value)

Given the parameter value, return a Python value suitable for serialization

+

Attributes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

compute_default_fn

check_on_set

names

allow_None

allow_refs

constant

default

doc

instantiate

label

name

nested_refs

objects

owner

per_instance

pickle_default_value

precedence

readonly

rx

watchers

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.Series.html b/reference/param/generated/param.Series.html new file mode 100644 index 0000000..a183057 --- /dev/null +++ b/reference/param/generated/param.Series.html @@ -0,0 +1,870 @@ + + + + + + + + + + + + param.Series — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.Series#

+
+
+class param.Series(default=None, *, rows=None, allow_None=False, instantiate=True, is_instance=True, doc=None, label=None, precedence=None, constant=False, readonly=False, pickle_default_value=True, per_instance=True, allow_refs=False, nested_refs=False)[source]#
+

Parameter whose value is a pandas Series.

+

The structure of the Series can be constrained by the rows argument +which may be a number or an integer bounds tuple to constrain the +allowable number of rows.

+
+
+__init__(default=None, *, rows=None, allow_None=False, is_instance=True, doc=None, label=None, precedence=None, instantiate=True, constant=False, readonly=False, pickle_default_value=True, per_instance=True, allow_refs=False, nested_refs=False)[source]#
+

Initialize a new Parameter object and store the supplied attributes:

+

default: the owning class’s value for the attribute represented +by this Parameter, which can be overridden in an instance.

+

doc: docstring explaining what this parameter represents.

+

label: optional text label to be used when this Parameter is +shown in a listing. If no label is supplied, the attribute name +for this parameter in the owning Parameterized object is used.

+

precedence: a numeric value, usually in the range 0.0 to 1.0, +which allows the order of Parameters in a class to be defined in +a listing or e.g. in GUI menus. A negative precedence indicates +a parameter that should be hidden in such listings.

+

instantiate: controls whether the value of this Parameter will +be deepcopied when a Parameterized object is instantiated (if +True), or if the single default value will be shared by all +Parameterized instances (if False). For an immutable Parameter +value, it is best to leave instantiate at the default of +False, so that a user can choose to change the value at the +Parameterized instance level (affecting only that instance) or +at the Parameterized class or superclass level (affecting all +existing and future instances of that class or superclass). For +a mutable Parameter value, the default of False is also appropriate +if you want all instances to share the same value state, e.g. if +they are each simply referring to a single global object like +a singleton. If instead each Parameterized should have its own +independently mutable value, instantiate should be set to +True, but note that there is then no simple way to change the +value of this Parameter at the class or superclass level, +because each instance, once created, will then have an +independently instantiated value.

+

constant: if true, the Parameter value can be changed only at +the class level or in a Parameterized constructor call. The +value is otherwise constant on the Parameterized instance, +once it has been constructed.

+

readonly: if true, the Parameter value cannot ordinarily be +changed by setting the attribute at the class or instance +levels at all. The value can still be changed in code by +temporarily overriding the value of this slot and then +restoring it, which is useful for reporting values that the +_user_ should never change but which do change during code +execution.

+

pickle_default_value: whether the default value should be +pickled. Usually, you would want the default value to be pickled, +but there are rare cases where that would not be the case (e.g. +for file search paths that are specific to a certain system).

+

per_instance: whether a separate Parameter instance will be +created for every Parameterized instance. True by default. +If False, all instances of a Parameterized class will share +the same Parameter object, including all validation +attributes (bounds, etc.). See also instantiate, which is +conceptually similar but affects the Parameter value rather +than the Parameter object.

+

allow_None: if True, None is accepted as a valid value for +this Parameter, in addition to any other values that are +allowed. If the default value is defined as None, allow_None +is set to True automatically.

+

allow_refs: if True allows automatically linking parameter +references to this Parameter, i.e. the parameter value will +automatically reflect the current value of the reference that +is passed in.

+

nested_refs: if True and allow_refs=True then even nested objects +such as dictionaries, lists, slices, tuples and sets will be +inspected for references and will be automatically resolved.

+

default, doc, and precedence all default to None, which allows +inheritance of Parameter slots (attributes) from the owning-class’ +class hierarchy (see ParameterizedMetaclass).

+
+ +

Methods

+ + + + + + + + + + + + + + + + + + +

__init__([default, rows, allow_None, ...])

Initialize a new Parameter object and store the supplied attributes:

deserialize(value)

Given a serializable Python value, return a value that the parameter can be set to

get_range()

Return the possible types for this parameter's value.

schema([safe, subset, mode])

serialize(value)

Given the parameter value, return a Python value suitable for serialization

+

Attributes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

rows

allow_None

allow_refs

class_

constant

default

doc

instantiate

is_instance

label

name

nested_refs

owner

per_instance

pickle_default_value

precedence

readonly

rx

watchers

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.String.html b/reference/param/generated/param.String.html new file mode 100644 index 0000000..41b55a0 --- /dev/null +++ b/reference/param/generated/param.String.html @@ -0,0 +1,866 @@ + + + + + + + + + + + + param.String — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.String#

+
+
+class param.String(default='', *, regex=None, doc=None, label=None, precedence=None, instantiate=False, constant=False, readonly=False, pickle_default_value=True, allow_None=False, per_instance=True, allow_refs=False, nested_refs=False)[source]#
+

A String Parameter, with a default value and optional regular expression (regex) matching.

+

Example of using a regex to implement IPv4 address matching:

+
class IPAddress(String):
+  '''IPv4 address as a string (dotted decimal notation)'''
+ def __init__(self, default="0.0.0.0", allow_None=False, **kwargs):
+     ip_regex = r'^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$'
+     super(IPAddress, self).__init__(default=default, regex=ip_regex, **kwargs)
+
+
+
+
+__init__(default='', *, regex=None, doc=None, label=None, precedence=None, instantiate=False, constant=False, readonly=False, pickle_default_value=True, allow_None=False, per_instance=True, allow_refs=False, nested_refs=False)[source]#
+

Initialize a new Parameter object and store the supplied attributes:

+

default: the owning class’s value for the attribute represented +by this Parameter, which can be overridden in an instance.

+

doc: docstring explaining what this parameter represents.

+

label: optional text label to be used when this Parameter is +shown in a listing. If no label is supplied, the attribute name +for this parameter in the owning Parameterized object is used.

+

precedence: a numeric value, usually in the range 0.0 to 1.0, +which allows the order of Parameters in a class to be defined in +a listing or e.g. in GUI menus. A negative precedence indicates +a parameter that should be hidden in such listings.

+

instantiate: controls whether the value of this Parameter will +be deepcopied when a Parameterized object is instantiated (if +True), or if the single default value will be shared by all +Parameterized instances (if False). For an immutable Parameter +value, it is best to leave instantiate at the default of +False, so that a user can choose to change the value at the +Parameterized instance level (affecting only that instance) or +at the Parameterized class or superclass level (affecting all +existing and future instances of that class or superclass). For +a mutable Parameter value, the default of False is also appropriate +if you want all instances to share the same value state, e.g. if +they are each simply referring to a single global object like +a singleton. If instead each Parameterized should have its own +independently mutable value, instantiate should be set to +True, but note that there is then no simple way to change the +value of this Parameter at the class or superclass level, +because each instance, once created, will then have an +independently instantiated value.

+

constant: if true, the Parameter value can be changed only at +the class level or in a Parameterized constructor call. The +value is otherwise constant on the Parameterized instance, +once it has been constructed.

+

readonly: if true, the Parameter value cannot ordinarily be +changed by setting the attribute at the class or instance +levels at all. The value can still be changed in code by +temporarily overriding the value of this slot and then +restoring it, which is useful for reporting values that the +_user_ should never change but which do change during code +execution.

+

pickle_default_value: whether the default value should be +pickled. Usually, you would want the default value to be pickled, +but there are rare cases where that would not be the case (e.g. +for file search paths that are specific to a certain system).

+

per_instance: whether a separate Parameter instance will be +created for every Parameterized instance. True by default. +If False, all instances of a Parameterized class will share +the same Parameter object, including all validation +attributes (bounds, etc.). See also instantiate, which is +conceptually similar but affects the Parameter value rather +than the Parameter object.

+

allow_None: if True, None is accepted as a valid value for +this Parameter, in addition to any other values that are +allowed. If the default value is defined as None, allow_None +is set to True automatically.

+

allow_refs: if True allows automatically linking parameter +references to this Parameter, i.e. the parameter value will +automatically reflect the current value of the reference that +is passed in.

+

nested_refs: if True and allow_refs=True then even nested objects +such as dictionaries, lists, slices, tuples and sets will be +inspected for references and will be automatically resolved.

+

default, doc, and precedence all default to None, which allows +inheritance of Parameter slots (attributes) from the owning-class’ +class hierarchy (see ParameterizedMetaclass).

+
+ +

Methods

+ + + + + + + + + + + + + + + +

__init__([default, regex, doc, label, ...])

Initialize a new Parameter object and store the supplied attributes:

deserialize(value)

Given a serializable Python value, return a value that the parameter can be set to

schema([safe, subset, mode])

serialize(value)

Given the parameter value, return a Python value suitable for serialization

+

Attributes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

regex

allow_None

allow_refs

constant

default

doc

instantiate

label

name

nested_refs

owner

per_instance

pickle_default_value

precedence

readonly

rx

watchers

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.Tuple.html b/reference/param/generated/param.Tuple.html new file mode 100644 index 0000000..df2060d --- /dev/null +++ b/reference/param/generated/param.Tuple.html @@ -0,0 +1,797 @@ + + + + + + + + + + + + param.Tuple — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.Tuple#

+
+
+class param.Tuple(default=(0, 0), *, length=None, doc=None, label=None, precedence=None, instantiate=False, constant=False, readonly=False, pickle_default_value=True, allow_None=False, per_instance=True, allow_refs=False, nested_refs=False)[source]#
+

A tuple Parameter (e.g. (‘a’,7.6,[3,5])) with a fixed tuple length.

+
+
+__init__(default=(0, 0), *, length=None, doc=None, label=None, precedence=None, instantiate=False, constant=False, readonly=False, pickle_default_value=True, allow_None=False, per_instance=True, allow_refs=False, nested_refs=False)[source]#
+

Initialize a tuple parameter with a fixed length (number of +elements). The length is determined by the initial default +value, if any, and must be supplied explicitly otherwise. The +length is not allowed to change after instantiation.

+
+ +

Methods

+ + + + + + + + + + + + + + + +

__init__([default, length, doc, label, ...])

Initialize a tuple parameter with a fixed length (number of elements).

deserialize(value)

Given a serializable Python value, return a value that the parameter can be set to

schema([safe, subset, mode])

serialize(value)

Given the parameter value, return a Python value suitable for serialization

+

Attributes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

length

allow_None

allow_refs

constant

default

doc

instantiate

label

name

nested_refs

owner

per_instance

pickle_default_value

precedence

readonly

rx

watchers

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.XYCoordinates.html b/reference/param/generated/param.XYCoordinates.html new file mode 100644 index 0000000..3b97646 --- /dev/null +++ b/reference/param/generated/param.XYCoordinates.html @@ -0,0 +1,797 @@ + + + + + + + + + + + + param.XYCoordinates — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.XYCoordinates#

+
+
+class param.XYCoordinates(default=(0.0, 0.0), *, length=None, doc=None, label=None, precedence=None, instantiate=False, constant=False, readonly=False, pickle_default_value=True, allow_None=False, per_instance=True, allow_refs=False, nested_refs=False)[source]#
+

A NumericTuple for an X,Y coordinate.

+
+
+__init__(default=(0.0, 0.0), *, length=None, allow_None=False, doc=None, label=None, precedence=None, instantiate=False, constant=False, readonly=False, pickle_default_value=True, per_instance=True, allow_refs=False, nested_refs=False)[source]#
+

Initialize a tuple parameter with a fixed length (number of +elements). The length is determined by the initial default +value, if any, and must be supplied explicitly otherwise. The +length is not allowed to change after instantiation.

+
+ +

Methods

+ + + + + + + + + + + + + + + +

__init__([default, length, allow_None, doc, ...])

Initialize a tuple parameter with a fixed length (number of elements).

deserialize(value)

Given a serializable Python value, return a value that the parameter can be set to

schema([safe, subset, mode])

serialize(value)

Given the parameter value, return a Python value suitable for serialization

+

Attributes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

allow_None

allow_refs

constant

default

doc

instantiate

label

length

name

nested_refs

owner

per_instance

pickle_default_value

precedence

readonly

rx

watchers

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.batch_watch.html b/reference/param/generated/param.batch_watch.html new file mode 100644 index 0000000..1102a6d --- /dev/null +++ b/reference/param/generated/param.batch_watch.html @@ -0,0 +1,711 @@ + + + + + + + + + + + + param.batch_watch — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.batch_watch#

+
+
+param.batch_watch(parameterized, enable=True, run=True)[source]#
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.concrete_descendents.html b/reference/param/generated/param.concrete_descendents.html new file mode 100644 index 0000000..ebb15e7 --- /dev/null +++ b/reference/param/generated/param.concrete_descendents.html @@ -0,0 +1,717 @@ + + + + + + + + + + + + param.concrete_descendents — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.concrete_descendents#

+
+
+param.concrete_descendents(parentclass)[source]#
+

Return a dictionary containing all subclasses of the specified +parentclass, including the parentclass. Only classes that are +defined in scripts that have been run or modules that have been +imported are included, so the caller will usually first do from +package import *.

+

Only non-abstract classes will be included.

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.depends.html b/reference/param/generated/param.depends.html new file mode 100644 index 0000000..7eb9b2d --- /dev/null +++ b/reference/param/generated/param.depends.html @@ -0,0 +1,727 @@ + + + + + + + + + + + + param.depends — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.depends#

+
+
+param.depends(func, *dependencies, watch=False, on_init=False, **kw)[source]#
+

Annotates a function or Parameterized method to express its dependencies.

+

The specified dependencies can be either be Parameter instances or if a +method is supplied they can be defined as strings referring to Parameters +of the class, or Parameters of subobjects (Parameterized objects that are +values of this object’s parameters). Dependencies can either be on +Parameter values, or on other metadata about the Parameter.

+
+
Parameters:
+
    +
  • watch (bool, optional) – Whether to invoke the function/method when the dependency is updated, +by default False

  • +
  • on_init (bool, optional) – Whether to invoke the function/method when the instance is created, +by default False

  • +
+
+
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.discard_events.html b/reference/param/generated/param.discard_events.html new file mode 100644 index 0000000..c5a7a18 --- /dev/null +++ b/reference/param/generated/param.discard_events.html @@ -0,0 +1,713 @@ + + + + + + + + + + + + param.discard_events — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.discard_events#

+
+
+param.discard_events(parameterized)[source]#
+

Context manager that discards any events within its scope +triggered on the supplied parameterized object.

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.edit_constant.html b/reference/param/generated/param.edit_constant.html new file mode 100644 index 0000000..fbca73e --- /dev/null +++ b/reference/param/generated/param.edit_constant.html @@ -0,0 +1,713 @@ + + + + + + + + + + + + param.edit_constant — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.edit_constant#

+
+
+param.edit_constant(parameterized)[source]#
+

Temporarily set parameters on Parameterized object to constant=False +to allow editing them.

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.get_soft_bounds.html b/reference/param/generated/param.get_soft_bounds.html new file mode 100644 index 0000000..083a801 --- /dev/null +++ b/reference/param/generated/param.get_soft_bounds.html @@ -0,0 +1,715 @@ + + + + + + + + + + + + param.get_soft_bounds — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.get_soft_bounds#

+
+
+param.get_soft_bounds(bounds, softbounds)[source]#
+

For each soft bound (upper and lower), if there is a defined bound +(not equal to None) and does not exceed the hard bound, then it is +returned. Otherwise it defaults to the hard bound. The hard bound +could still be None.

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.guess_bounds.html b/reference/param/generated/param.guess_bounds.html new file mode 100644 index 0000000..10794e5 --- /dev/null +++ b/reference/param/generated/param.guess_bounds.html @@ -0,0 +1,714 @@ + + + + + + + + + + + + param.guess_bounds — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.guess_bounds#

+
+
+param.guess_bounds(params, **overrides)[source]#
+

Given a dictionary of Parameter instances, return a corresponding +set of copies with the bounds appropriately set.

+

If given a set of override keywords, use those numeric tuple bounds.

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.guess_param_types.html b/reference/param/generated/param.guess_param_types.html new file mode 100644 index 0000000..c627f23 --- /dev/null +++ b/reference/param/generated/param.guess_param_types.html @@ -0,0 +1,713 @@ + + + + + + + + + + + + param.guess_param_types — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.guess_param_types#

+
+
+param.guess_param_types(**kwargs)[source]#
+

Given a set of keyword literals, promote to the appropriate +parameter type based on some simple heuristics.

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.output.html b/reference/param/generated/param.output.html new file mode 100644 index 0000000..4660bcd --- /dev/null +++ b/reference/param/generated/param.output.html @@ -0,0 +1,744 @@ + + + + + + + + + + + + param.output — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.output#

+
+
+param.output(func, *output, **kw)[source]#
+

output allows annotating a method on a Parameterized class to +declare that it returns an output of a specific type. The outputs +of a Parameterized class can be queried using the +Parameterized.param.outputs method. By default the output will +inherit the method name but a custom name can be declared by +expressing the Parameter type using a keyword argument.

+

The simplest declaration simply declares the method returns an +object without any type guarantees, e.g.:

+
+

@output()

+
+

If a specific parameter type is specified this is a declaration +that the method will return a value of that type, e.g.:

+
+

@output(param.Number())

+
+

To override the default name of the output the type may be declared +as a keyword argument, e.g.:

+
+

@output(custom_name=param.Number())

+
+

Multiple outputs may be declared using keywords mapping from output name +to the type or using tuples of the same format, i.e. these two declarations +are equivalent:

+
+

@output(number=param.Number(), string=param.String())

+

@output((‘number’, param.Number()), (‘string’, param.String()))

+
+

output also accepts Python object types which will be upgraded to +a ClassSelector, e.g.:

+
+

@output(int)

+
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.param_union.html b/reference/param/generated/param.param_union.html new file mode 100644 index 0000000..4e76664 --- /dev/null +++ b/reference/param/generated/param.param_union.html @@ -0,0 +1,725 @@ + + + + + + + + + + + + param.param_union — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.param_union#

+
+
+param.param_union(*parameterizeds, warn=True)[source]#
+

Given a set of Parameterized objects, returns a dictionary +with the union of all param name,value pairs across them.

+
+
Parameters:
+

warn (bool, optional) – Wether to warn if the same parameter have been given multiple values, +otherwise use the last value, by default True

+
+
Returns:
+

Union of all param name,value pairs

+
+
Return type:
+

dict

+
+
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.parameterized.Event.html b/reference/param/generated/param.parameterized.Event.html new file mode 100644 index 0000000..26568f3 --- /dev/null +++ b/reference/param/generated/param.parameterized.Event.html @@ -0,0 +1,769 @@ + + + + + + + + + + + + param.parameterized.Event — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.parameterized.Event#

+
+
+class param.parameterized.Event(what, name, obj, cls, old, new, type)#
+

Object representing an event that triggers a Watcher.

+

what: What is being watched on the Parameter (either value or a slot name)

+

name: Name of the Parameter that was set or triggered

+

obj: Parameterized instance owning the watched Parameter, or None

+

cls: Parameterized class owning the watched Parameter

+

old: Previous value of the item being watched

+

new: New value of the item being watched

+

type: triggered if this event was triggered explicitly), changed if +the item was set and watching for onlychanged, set if the item was set, +or None if type not yet known

+
+
+__init__()#
+
+ +

Methods

+ + + + + + + + + + + + +

__init__()

count(value, /)

Return number of occurrences of value.

index(value[, start, stop])

Return first index of value.

+

Attributes

+ + + + + + + + + + + + + + + + + + + + + + + + +

cls

Alias for field number 3

name

Alias for field number 1

new

Alias for field number 5

obj

Alias for field number 2

old

Alias for field number 4

type

Alias for field number 6

what

Alias for field number 0

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.parameterized.Parameters.add_parameter.html b/reference/param/generated/param.parameterized.Parameters.add_parameter.html new file mode 100644 index 0000000..7b5937f --- /dev/null +++ b/reference/param/generated/param.parameterized.Parameters.add_parameter.html @@ -0,0 +1,714 @@ + + + + + + + + + + + + param.parameterized.Parameters.add_parameter — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.parameterized.Parameters.add_parameter#

+
+
+Parameters.add_parameter(param_name, param_obj)[source]#
+

Add a new Parameter object into this object’s class.

+

Should result in a Parameter equivalent to one declared +in the class’s source code.

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.parameterized.Parameters.debug.html b/reference/param/generated/param.parameterized.Parameters.debug.html new file mode 100644 index 0000000..87b2ef0 --- /dev/null +++ b/reference/param/generated/param.parameterized.Parameters.debug.html @@ -0,0 +1,716 @@ + + + + + + + + + + + + param.parameterized.Parameters.debug — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.parameterized.Parameters.debug#

+
+
+Parameters.debug(msg, *args, **kw)[source]#
+

Print msg merged with args as a debugging statement.

+

See Python’s logging module for details of message formatting.

+
+

Deprecated since version 1.12.0: Use instead .param.log(param.DEBUG, …)

+
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.parameterized.Parameters.defaults.html b/reference/param/generated/param.parameterized.Parameters.defaults.html new file mode 100644 index 0000000..2200b6a --- /dev/null +++ b/reference/param/generated/param.parameterized.Parameters.defaults.html @@ -0,0 +1,718 @@ + + + + + + + + + + + + param.parameterized.Parameters.defaults — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.parameterized.Parameters.defaults#

+
+
+Parameters.defaults()[source]#
+

Return {parameter_name:parameter.default} for all non-constant +Parameters.

+

Note that a Parameter for which instantiate==True has its default +instantiated.

+
+

Deprecated since version 1.12.0: Use instead {k:v.default for k,v in p.param.objects().items()}

+
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.parameterized.Parameters.deserialize_parameters.html b/reference/param/generated/param.parameterized.Parameters.deserialize_parameters.html new file mode 100644 index 0000000..5981102 --- /dev/null +++ b/reference/param/generated/param.parameterized.Parameters.deserialize_parameters.html @@ -0,0 +1,711 @@ + + + + + + + + + + + + param.parameterized.Parameters.deserialize_parameters — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.parameterized.Parameters.deserialize_parameters#

+
+
+Parameters.deserialize_parameters(serialization, subset=None, mode='json')[source]#
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.parameterized.Parameters.deserialize_value.html b/reference/param/generated/param.parameterized.Parameters.deserialize_value.html new file mode 100644 index 0000000..2edebbf --- /dev/null +++ b/reference/param/generated/param.parameterized.Parameters.deserialize_value.html @@ -0,0 +1,711 @@ + + + + + + + + + + + + param.parameterized.Parameters.deserialize_value — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.parameterized.Parameters.deserialize_value#

+
+
+Parameters.deserialize_value(pname, value, mode='json')[source]#
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.parameterized.Parameters.force_new_dynamic_value.html b/reference/param/generated/param.parameterized.Parameters.force_new_dynamic_value.html new file mode 100644 index 0000000..42dff90 --- /dev/null +++ b/reference/param/generated/param.parameterized.Parameters.force_new_dynamic_value.html @@ -0,0 +1,715 @@ + + + + + + + + + + + + param.parameterized.Parameters.force_new_dynamic_value — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.parameterized.Parameters.force_new_dynamic_value#

+
+
+Parameters.force_new_dynamic_value(name)[source]#
+

Force a new value to be generated for the dynamic attribute +name, and return it.

+

If name is not dynamic, its current value is returned +(i.e. equivalent to getattr(name).

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.parameterized.Parameters.get_param_values.html b/reference/param/generated/param.parameterized.Parameters.get_param_values.html new file mode 100644 index 0000000..65a7716 --- /dev/null +++ b/reference/param/generated/param.parameterized.Parameters.get_param_values.html @@ -0,0 +1,720 @@ + + + + + + + + + + + + param.parameterized.Parameters.get_param_values — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.parameterized.Parameters.get_param_values#

+
+
+Parameters.get_param_values(onlychanged=False)[source]#
+

Return a list of name,value pairs for all Parameters of this +object.

+

When called on an instance with onlychanged set to True, will +only return values that are not equal to the default value +(onlychanged has no effect when called on a class).

+
+

Deprecated since version 1.12.0: Use .param.values().items() instead (or .param.values() for the +common case of dict(….param.get_param_values()))

+
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.parameterized.Parameters.get_value_generator.html b/reference/param/generated/param.parameterized.Parameters.get_value_generator.html new file mode 100644 index 0000000..0920973 --- /dev/null +++ b/reference/param/generated/param.parameterized.Parameters.get_value_generator.html @@ -0,0 +1,716 @@ + + + + + + + + + + + + param.parameterized.Parameters.get_value_generator — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.parameterized.Parameters.get_value_generator#

+
+
+Parameters.get_value_generator(name)[source]#
+

Return the value or value-generating object of the named +attribute.

+

For most parameters, this is simply the parameter’s value +(i.e. the same as getattr()), but Dynamic parameters have +their value-generating object returned.

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.parameterized.Parameters.inspect_value.html b/reference/param/generated/param.parameterized.Parameters.inspect_value.html new file mode 100644 index 0000000..9f4aa23 --- /dev/null +++ b/reference/param/generated/param.parameterized.Parameters.inspect_value.html @@ -0,0 +1,714 @@ + + + + + + + + + + + + param.parameterized.Parameters.inspect_value — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.parameterized.Parameters.inspect_value#

+
+
+Parameters.inspect_value(name)[source]#
+

Return the current value of the named attribute without modifying it.

+

Same as getattr() except for Dynamic parameters, which have their +last generated value returned.

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.parameterized.Parameters.log.html b/reference/param/generated/param.parameterized.Parameters.log.html new file mode 100644 index 0000000..b5bb211 --- /dev/null +++ b/reference/param/generated/param.parameterized.Parameters.log.html @@ -0,0 +1,718 @@ + + + + + + + + + + + + param.parameterized.Parameters.log — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.parameterized.Parameters.log#

+
+
+Parameters.log(level, msg, *args, **kw)[source]#
+

Print msg merged with args as a message at the indicated logging level.

+

Logging levels include those provided by the Python logging module +plus VERBOSE, either obtained directly from the logging module like +logging.INFO, or from parameterized like param.parameterized.INFO.

+

Supported logging levels include (in order of severity) +DEBUG, VERBOSE, INFO, WARNING, ERROR, CRITICAL

+

See Python’s logging module for details of message formatting.

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.parameterized.Parameters.message.html b/reference/param/generated/param.parameterized.Parameters.message.html new file mode 100644 index 0000000..e771681 --- /dev/null +++ b/reference/param/generated/param.parameterized.Parameters.message.html @@ -0,0 +1,716 @@ + + + + + + + + + + + + param.parameterized.Parameters.message — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.parameterized.Parameters.message#

+
+
+Parameters.message(msg, *args, **kw)[source]#
+

Print msg merged with args as a message.

+

See Python’s logging module for details of message formatting.

+
+

Deprecated since version 1.12.0: Use instead .param.log(param.MESSAGE, …)

+
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.parameterized.Parameters.method_dependencies.html b/reference/param/generated/param.parameterized.Parameters.method_dependencies.html new file mode 100644 index 0000000..16a5432 --- /dev/null +++ b/reference/param/generated/param.parameterized.Parameters.method_dependencies.html @@ -0,0 +1,716 @@ + + + + + + + + + + + + param.parameterized.Parameters.method_dependencies — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.parameterized.Parameters.method_dependencies#

+
+
+Parameters.method_dependencies(name, intermediate=False)[source]#
+

Given the name of a method, returns a PInfo object for each dependency +of this method. See help(PInfo) for the contents of these objects.

+

By default intermediate dependencies on sub-objects are not +returned as these are primarily useful for internal use to +determine when a sub-object dependency has to be updated.

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.parameterized.Parameters.objects.html b/reference/param/generated/param.parameterized.Parameters.objects.html new file mode 100644 index 0000000..41c608a --- /dev/null +++ b/reference/param/generated/param.parameterized.Parameters.objects.html @@ -0,0 +1,719 @@ + + + + + + + + + + + + param.parameterized.Parameters.objects — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.parameterized.Parameters.objects#

+
+
+Parameters.objects(instance=True)[source]#
+

Returns the Parameters of this instance or class

+

If instance=True and called on a Parameterized instance it +will create instance parameters for all Parameters defined on +the class. To force class parameters to be returned use +instance=False. Since classes avoid creating instance +parameters unless necessary you may also request only existing +instance parameters to be returned by setting +instance=’existing’.

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.parameterized.Parameters.outputs.html b/reference/param/generated/param.parameterized.Parameters.outputs.html new file mode 100644 index 0000000..d6fe718 --- /dev/null +++ b/reference/param/generated/param.parameterized.Parameters.outputs.html @@ -0,0 +1,714 @@ + + + + + + + + + + + + param.parameterized.Parameters.outputs — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.parameterized.Parameters.outputs#

+
+
+Parameters.outputs()[source]#
+

Returns a mapping between any declared outputs and a tuple +of the declared Parameter type, the output method, and the +index into the output if multiple outputs are returned.

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.parameterized.Parameters.params.html b/reference/param/generated/param.parameterized.Parameters.params.html new file mode 100644 index 0000000..9633d95 --- /dev/null +++ b/reference/param/generated/param.parameterized.Parameters.params.html @@ -0,0 +1,718 @@ + + + + + + + + + + + + param.parameterized.Parameters.params — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.parameterized.Parameters.params#

+
+
+Parameters.params(parameter_name=None)[source]#
+

Return the Parameters of this class as the +dictionary {name: parameter_object}

+

Includes Parameters from this class and its +superclasses.

+
+

Deprecated since version 1.12.0: Use instead .param.values() or .param[‘param’]

+
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.parameterized.Parameters.params_depended_on.html b/reference/param/generated/param.parameterized.Parameters.params_depended_on.html new file mode 100644 index 0000000..257d64c --- /dev/null +++ b/reference/param/generated/param.parameterized.Parameters.params_depended_on.html @@ -0,0 +1,716 @@ + + + + + + + + + + + + param.parameterized.Parameters.params_depended_on — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.parameterized.Parameters.params_depended_on#

+
+
+Parameters.params_depended_on(*args, **kwargs)[source]#
+

Given the name of a method, returns a PInfo object for each dependency +of this method. See help(PInfo) for the contents of these objects.

+

By default intermediate dependencies on sub-objects are not +returned as these are primarily useful for internal use to +determine when a sub-object dependency has to be updated.

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.parameterized.Parameters.pprint.html b/reference/param/generated/param.parameterized.Parameters.pprint.html new file mode 100644 index 0000000..b5c77c3 --- /dev/null +++ b/reference/param/generated/param.parameterized.Parameters.pprint.html @@ -0,0 +1,713 @@ + + + + + + + + + + + + param.parameterized.Parameters.pprint — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.parameterized.Parameters.pprint#

+
+
+Parameters.pprint(imports=None, prefix=' ', unknown_value='<?>', qualify=False, separator='')[source]#
+

(Experimental) Pretty printed representation that may be +evaluated with eval. See pprint() function for more details.

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.parameterized.Parameters.print_param_defaults.html b/reference/param/generated/param.parameterized.Parameters.print_param_defaults.html new file mode 100644 index 0000000..db6c935 --- /dev/null +++ b/reference/param/generated/param.parameterized.Parameters.print_param_defaults.html @@ -0,0 +1,715 @@ + + + + + + + + + + + + param.parameterized.Parameters.print_param_defaults — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.parameterized.Parameters.print_param_defaults#

+
+
+Parameters.print_param_defaults()[source]#
+

Print the default values of all cls’s Parameters.

+
+

Deprecated since version 1.12.0: Use instead for k,v in p.param.objects().items(): print(f”{p.__class__.name}.{k}={repr(v.default)}”)

+
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.parameterized.Parameters.print_param_values.html b/reference/param/generated/param.parameterized.Parameters.print_param_values.html new file mode 100644 index 0000000..9fc6fe9 --- /dev/null +++ b/reference/param/generated/param.parameterized.Parameters.print_param_values.html @@ -0,0 +1,715 @@ + + + + + + + + + + + + param.parameterized.Parameters.print_param_values — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.parameterized.Parameters.print_param_values#

+
+
+Parameters.print_param_values()[source]#
+

Print the values of all this object’s Parameters.

+
+

Deprecated since version 1.12.0: Use instead for k,v in p.param.objects().items(): print(f”{p.__class__.name}.{k}={repr(v.default)}”)

+
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.parameterized.Parameters.schema.html b/reference/param/generated/param.parameterized.Parameters.schema.html new file mode 100644 index 0000000..8002e03 --- /dev/null +++ b/reference/param/generated/param.parameterized.Parameters.schema.html @@ -0,0 +1,712 @@ + + + + + + + + + + + + param.parameterized.Parameters.schema — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.parameterized.Parameters.schema#

+
+
+Parameters.schema(safe=False, subset=None, mode='json')[source]#
+

Returns a schema for the parameters on this Parameterized object.

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.parameterized.Parameters.serialize_parameters.html b/reference/param/generated/param.parameterized.Parameters.serialize_parameters.html new file mode 100644 index 0000000..4c80adc --- /dev/null +++ b/reference/param/generated/param.parameterized.Parameters.serialize_parameters.html @@ -0,0 +1,711 @@ + + + + + + + + + + + + param.parameterized.Parameters.serialize_parameters — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.parameterized.Parameters.serialize_parameters#

+
+
+Parameters.serialize_parameters(subset=None, mode='json')[source]#
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.parameterized.Parameters.serialize_value.html b/reference/param/generated/param.parameterized.Parameters.serialize_value.html new file mode 100644 index 0000000..6b1a186 --- /dev/null +++ b/reference/param/generated/param.parameterized.Parameters.serialize_value.html @@ -0,0 +1,711 @@ + + + + + + + + + + + + param.parameterized.Parameters.serialize_value — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.parameterized.Parameters.serialize_value#

+
+
+Parameters.serialize_value(pname, mode='json')[source]#
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.parameterized.Parameters.set_default.html b/reference/param/generated/param.parameterized.Parameters.set_default.html new file mode 100644 index 0000000..d831f3c --- /dev/null +++ b/reference/param/generated/param.parameterized.Parameters.set_default.html @@ -0,0 +1,716 @@ + + + + + + + + + + + + param.parameterized.Parameters.set_default — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.parameterized.Parameters.set_default#

+
+
+Parameters.set_default(param_name, value)[source]#
+

Set the default value of param_name.

+

Equivalent to setting param_name on the class.

+
+

Deprecated since version 1.12.0: Use instead p.param.default =

+
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.parameterized.Parameters.set_dynamic_time_fn.html b/reference/param/generated/param.parameterized.Parameters.set_dynamic_time_fn.html new file mode 100644 index 0000000..4741956 --- /dev/null +++ b/reference/param/generated/param.parameterized.Parameters.set_dynamic_time_fn.html @@ -0,0 +1,724 @@ + + + + + + + + + + + + param.parameterized.Parameters.set_dynamic_time_fn — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.parameterized.Parameters.set_dynamic_time_fn#

+
+
+Parameters.set_dynamic_time_fn(time_fn, sublistattr=None)[source]#
+

Set time_fn for all Dynamic Parameters of this class or +instance object that are currently being dynamically +generated.

+

Additionally, sets _Dynamic_time_fn=time_fn on this class or +instance object, so that any future changes to Dynamic +Parmeters can inherit time_fn (e.g. if a Number is changed +from a float to a number generator, the number generator will +inherit time_fn).

+

If specified, sublistattr is the name of an attribute of this +class or instance that contains an iterable collection of +subobjects on which set_dynamic_time_fn should be called. If +the attribute sublistattr is present on any of the subobjects, +set_dynamic_time_fn() will be called for those, too.

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.parameterized.Parameters.set_param.html b/reference/param/generated/param.parameterized.Parameters.set_param.html new file mode 100644 index 0000000..8d81901 --- /dev/null +++ b/reference/param/generated/param.parameterized.Parameters.set_param.html @@ -0,0 +1,720 @@ + + + + + + + + + + + + param.parameterized.Parameters.set_param — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.parameterized.Parameters.set_param#

+
+
+Parameters.set_param(*args, **kwargs)[source]#
+

For each param=value keyword argument, sets the corresponding +parameter of this object or class to the given value.

+

For backwards compatibility, also accepts +set_param(“param”,value) for a single parameter value using +positional arguments, but the keyword interface is preferred +because it is more compact and can set multiple values.

+
+

Deprecated since version 1.12.0: Use instead .param.update

+
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.parameterized.Parameters.trigger.html b/reference/param/generated/param.parameterized.Parameters.trigger.html new file mode 100644 index 0000000..11e2f6b --- /dev/null +++ b/reference/param/generated/param.parameterized.Parameters.trigger.html @@ -0,0 +1,716 @@ + + + + + + + + + + + + param.parameterized.Parameters.trigger — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.parameterized.Parameters.trigger#

+
+
+Parameters.trigger(*param_names)[source]#
+

Trigger watchers for the given set of parameter names. Watchers +will be triggered whether or not the parameter values have +actually changed. As a special case, the value will actually be +changed for a Parameter of type Event, setting it to True so +that it is clear which Event parameter has been triggered.

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.parameterized.Parameters.unwatch.html b/reference/param/generated/param.parameterized.Parameters.unwatch.html new file mode 100644 index 0000000..1487d08 --- /dev/null +++ b/reference/param/generated/param.parameterized.Parameters.unwatch.html @@ -0,0 +1,712 @@ + + + + + + + + + + + + param.parameterized.Parameters.unwatch — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.parameterized.Parameters.unwatch#

+
+
+Parameters.unwatch(watcher)[source]#
+

Remove the given Watcher object (from watch or watch_values) from this object’s list.

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.parameterized.Parameters.update.html b/reference/param/generated/param.parameterized.Parameters.update.html new file mode 100644 index 0000000..c4c0feb --- /dev/null +++ b/reference/param/generated/param.parameterized.Parameters.update.html @@ -0,0 +1,716 @@ + + + + + + + + + + + + param.parameterized.Parameters.update — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.parameterized.Parameters.update#

+
+
+Parameters.update(*args, **kwargs)[source]#
+

For the given dictionary or iterable or set of param=value +keyword arguments, sets the corresponding parameter of this +object or class to the given value.

+

May also be used as a context manager to temporarily set and +then reset parameter values.

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.parameterized.Parameters.values.html b/reference/param/generated/param.parameterized.Parameters.values.html new file mode 100644 index 0000000..46d8813 --- /dev/null +++ b/reference/param/generated/param.parameterized.Parameters.values.html @@ -0,0 +1,716 @@ + + + + + + + + + + + + param.parameterized.Parameters.values — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.parameterized.Parameters.values#

+
+
+Parameters.values(onlychanged=False)[source]#
+

Return a dictionary of name,value pairs for the Parameters of this +object.

+

When called on an instance with onlychanged set to True, will +only return values that are not equal to the default value +(onlychanged has no effect when called on a class).

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.parameterized.Parameters.verbose.html b/reference/param/generated/param.parameterized.Parameters.verbose.html new file mode 100644 index 0000000..7a9ce34 --- /dev/null +++ b/reference/param/generated/param.parameterized.Parameters.verbose.html @@ -0,0 +1,716 @@ + + + + + + + + + + + + param.parameterized.Parameters.verbose — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.parameterized.Parameters.verbose#

+
+
+Parameters.verbose(msg, *args, **kw)[source]#
+

Print msg merged with args as a verbose message.

+

See Python’s logging module for details of message formatting.

+
+

Deprecated since version 1.12.0: Use instead .param.log(param.VERBOSE, …)

+
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.parameterized.Parameters.warning.html b/reference/param/generated/param.parameterized.Parameters.warning.html new file mode 100644 index 0000000..ee413ff --- /dev/null +++ b/reference/param/generated/param.parameterized.Parameters.warning.html @@ -0,0 +1,715 @@ + + + + + + + + + + + + param.parameterized.Parameters.warning — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.parameterized.Parameters.warning#

+
+
+Parameters.warning(msg, *args, **kw)[source]#
+

Print msg merged with args as a warning, unless module variable +warnings_as_exceptions is True, then raise an Exception +containing the arguments.

+

See Python’s logging module for details of message formatting.

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.parameterized.Parameters.watch.html b/reference/param/generated/param.parameterized.Parameters.watch.html new file mode 100644 index 0000000..dd6be70 --- /dev/null +++ b/reference/param/generated/param.parameterized.Parameters.watch.html @@ -0,0 +1,738 @@ + + + + + + + + + + + + param.parameterized.Parameters.watch — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.parameterized.Parameters.watch#

+
+
+Parameters.watch(fn, parameter_names, what='value', onlychanged=True, queued=False, precedence=0)[source]#
+

Register the given callback function fn to be invoked for +events on the indicated parameters.

+

what: What to watch on each parameter; either the value (by +default) or else the indicated slot (e.g. ‘constant’).

+

onlychanged: By default, only invokes the function when the +watched item changes, but if onlychanged=False also invokes +it when the what item is set to its current value again.

+

queued: By default, additional watcher events generated +inside the callback fn are dispatched immediately, effectively +doing depth-first processing of Watcher events. However, in +certain scenarios, it is helpful to wait to dispatch such +downstream events until all events that triggered this watcher +have been processed. In such cases setting queued=True on +this Watcher will queue up new downstream events generated +during fn until fn completes and all other watchers +invoked by that same event have finished executing), +effectively doing breadth-first processing of Watcher events.

+

precedence: Declares a precedence level for the Watcher that +determines the priority with which the callback is executed. +Lower precedence levels are executed earlier. Negative +precedences are reserved for internal Watchers, i.e. those +set up by param.depends.

+

When the fn is called, it will be provided the relevant +Event objects as positional arguments, which allows it to +determine which of the possible triggering events occurred.

+

Returns a Watcher object.

+

See help(Watcher) and help(Event) for the contents of those objects.

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.parameterized.Parameters.watch_values.html b/reference/param/generated/param.parameterized.Parameters.watch_values.html new file mode 100644 index 0000000..a6ef8ad --- /dev/null +++ b/reference/param/generated/param.parameterized.Parameters.watch_values.html @@ -0,0 +1,714 @@ + + + + + + + + + + + + param.parameterized.Parameters.watch_values — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.parameterized.Parameters.watch_values#

+
+
+Parameters.watch_values(fn, parameter_names, what='value', onlychanged=True, queued=False, precedence=0)[source]#
+

Easier-to-use version of watch specific to watching for changes in parameter values.

+

Only allows what to be ‘value’, and invokes the callback fn using keyword +arguments <param_name>=<new_value> rather than with a list of Event objects.

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.parameterized.Parameters.watchers.html b/reference/param/generated/param.parameterized.Parameters.watchers.html new file mode 100644 index 0000000..def8628 --- /dev/null +++ b/reference/param/generated/param.parameterized.Parameters.watchers.html @@ -0,0 +1,712 @@ + + + + + + + + + + + + param.parameterized.Parameters.watchers — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.parameterized.Parameters.watchers#

+
+
+property Parameters.watchers#
+

Dictionary of instance watchers.

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.parameterized.Watcher.html b/reference/param/generated/param.parameterized.Watcher.html new file mode 100644 index 0000000..6802adf --- /dev/null +++ b/reference/param/generated/param.parameterized.Watcher.html @@ -0,0 +1,788 @@ + + + + + + + + + + + + param.parameterized.Watcher — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.parameterized.Watcher#

+
+
+class param.parameterized.Watcher(*args, **kwargs)[source]#
+

Object declaring a callback function to invoke when an Event is +triggered on a watched item.

+

inst: Parameterized instance owning the watched Parameter, or +None

+

cls: Parameterized class owning the watched Parameter

+

fn: Callback function to invoke when triggered by a watched +Parameter

+

mode: ‘args’ for param.watch (call fn with PInfo object +positional args), or ‘kwargs’ for param.watch_values (call fn +with <param_name>:<new_value> keywords)

+

onlychanged: If True, only trigger for actual changes, not +setting to the current value

+

parameter_names: List of Parameters to watch, by name

+

what: What to watch on the Parameters (either ‘value’ or a slot +name)

+
+
queued: Immediately invoke callbacks triggered during processing

of an Event (if False), or queue them up for processing +later, after this event has been handled (if True)

+
+
precedence: A numeric value which determines the precedence of

the watcher. Lower precedence values are executed +with higher priority.

+
+
+
+
+__init__()#
+
+ +

Methods

+ + + + + + + + + + + + +

__init__()

count(value, /)

Return number of occurrences of value.

index(value[, start, stop])

Return first index of value.

+

Attributes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

cls

Alias for field number 1

fn

Alias for field number 2

inst

Alias for field number 0

mode

Alias for field number 3

onlychanged

Alias for field number 4

parameter_names

Alias for field number 5

precedence

Alias for field number 8

queued

Alias for field number 7

what

Alias for field number 6

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.parameterized.batch_call_watchers.html b/reference/param/generated/param.parameterized.batch_call_watchers.html new file mode 100644 index 0000000..1bb30e2 --- /dev/null +++ b/reference/param/generated/param.parameterized.batch_call_watchers.html @@ -0,0 +1,716 @@ + + + + + + + + + + + + param.parameterized.batch_call_watchers — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.parameterized.batch_call_watchers#

+
+
+param.parameterized.batch_call_watchers(parameterized)[source]#
+

Context manager to batch events to provide to Watchers on a +parameterized object. This context manager queues any events +triggered by setting a parameter on the supplied parameterized +object, saving them up to dispatch them all at once when the +context manager exits.

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.parameterized.get_logger.html b/reference/param/generated/param.parameterized.get_logger.html new file mode 100644 index 0000000..dc4c7f2 --- /dev/null +++ b/reference/param/generated/param.parameterized.get_logger.html @@ -0,0 +1,711 @@ + + + + + + + + + + + + param.parameterized.get_logger — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.parameterized.get_logger#

+
+
+param.parameterized.get_logger(name=None)[source]#
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.parameterized.logging_level.html b/reference/param/generated/param.parameterized.logging_level.html new file mode 100644 index 0000000..7794ccc --- /dev/null +++ b/reference/param/generated/param.parameterized.logging_level.html @@ -0,0 +1,712 @@ + + + + + + + + + + + + param.parameterized.logging_level — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.parameterized.logging_level#

+
+
+param.parameterized.logging_level(level)[source]#
+

Temporarily modify param’s logging level.

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/generated/param.script_repr.html b/reference/param/generated/param.script_repr.html new file mode 100644 index 0000000..1d1b8b5 --- /dev/null +++ b/reference/param/generated/param.script_repr.html @@ -0,0 +1,733 @@ + + + + + + + + + + + + param.script_repr — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

param.script_repr#

+
+
+param.script_repr(val, imports=None, prefix='\n    ', settings=[], qualify=True, unknown_value=None, separator='\n', show_imports=True)[source]#
+

Variant of pprint() designed for generating a (nearly) runnable script.

+

The output of script_repr(parameterized_obj) is meant to be a +string suitable for running using python file.py. Not every +object is guaranteed to have a runnable script_repr +representation, but it is meant to be a good starting point for +generating a Python script that (after minor edits) can be +evaluated to get a newly initialized object similar to the one +provided.

+

The new object will only have the same parameter state, not the +same internal (attribute) state; the script_repr captures only +the state of the Parameters of that object and not any other +attributes it may have.

+

If show_imports is True (default), includes import statements +for each of the modules required for the objects being +instantiated. This list may not be complete, as it typically +includes only the imports needed for the Parameterized object +itself, not for values that may have been supplied to Parameters.

+

Apart from show_imports, accepts the same arguments as pprint(), +so see pprint() for explanations of the arguments accepted. The +default values of each of these arguments differ from pprint() in +ways that are more suitable for saving as a separate script than +for e.g. pretty-printing at the Python prompt.

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/index.html b/reference/param/index.html new file mode 100644 index 0000000..5a64fc6 --- /dev/null +++ b/reference/param/index.html @@ -0,0 +1,1285 @@ + + + + + + + + + + + + Param API reference — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

Param API reference#

+
+

Parameterized objects#

+ + + + + + + + + +

Parameterized

Base class for named objects that support Parameters and message formatting.

ParameterizedFunction

Acts like a Python function, but with arguments that are Parameters.

+
+
+

Parameterized helpers#

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

param.parameterized.Event(what, name, obj, ...)

Object representing an event that triggers a Watcher.

param.parameterized.Watcher(*args, **kwargs)

Object declaring a callback function to invoke when an Event is triggered on a watched item.

batch_watch(parameterized[, enable, run])

param.parameterized.batch_call_watchers(...)

Context manager to batch events to provide to Watchers on a parameterized object.

concrete_descendents(parentclass)

Return a dictionary containing all subclasses of the specified parentclass, including the parentclass.

depends(func, *dependencies[, watch, on_init])

Annotates a function or Parameterized method to express its dependencies.

discard_events(parameterized)

Context manager that discards any events within its scope triggered on the supplied parameterized object.

edit_constant(parameterized)

Temporarily set parameters on Parameterized object to constant=False to allow editing them.

output(func, *output, **kw)

output allows annotating a method on a Parameterized class to declare that it returns an output of a specific type.

script_repr(val[, imports, prefix, ...])

Variant of pprint() designed for generating a (nearly) runnable script.

+
+
+

Parameters#

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Parameter

An attribute descriptor for declaring parameters.

String

A String Parameter, with a default value and optional regular expression (regex) matching.

Bytes

A Bytes Parameter, with a default value and optional regular expression (regex) matching.

Color

Color parameter defined as a hex RGB string with an optional # prefix or (optionally) as a CSS3 color name.

Boolean

Binary or tristate Boolean Parameter.

Event

An Event Parameter is one whose value is intimately linked to the triggering of events for watchers to consume.

Dynamic

Parameter whose value can be generated dynamically by a callable object.

Number

A numeric Dynamic Parameter, with a default value and optional bounds.

Integer

Numeric Parameter required to be an Integer

Magnitude

Numeric Parameter required to be in the range [0.0-1.0].

Tuple

A tuple Parameter (e.g.

NumericTuple

A numeric tuple Parameter (e.g.

XYCoordinates

A NumericTuple for an X,Y coordinate.

Range

A numeric range with optional bounds and softbounds.

DateRange

A datetime or date range specified as (start, end).

CalendarDateRange

A date range specified as (start_date, end_date).

List

Parameter whose value is a list of objects, usually of a specified type.

HookList

Parameter whose value is a list of callable objects.

Path

Parameter that can be set to a string specifying the path of a file or folder.

Filename

Parameter that can be set to a string specifying the path of a file.

Foldername

Parameter that can be set to a string specifying the path of a folder.

CalendarDateRange

A date range specified as (start_date, end_date).

Selector

Parameter whose value must be one object from a list of possible objects.

FileSelector

Given a path glob, allows one file to be selected from those matching.

ListSelector

Variant of Selector where the value can be multiple objects from a list of possible objects.

MultiFileSelector

Given a path glob, allows multiple files to be selected from the list of matches.

ClassSelector

Parameter allowing selection of either a subclass or an instance of a given set of classes.

Dict

Parameter whose value is a dictionary.

Array

Parameter whose value is a numpy array.

Series

Parameter whose value is a pandas Series.

DataFrame

Parameter whose value is a pandas DataFrame.

Callable

Parameter holding a value that is a callable object, such as a function.

Action

A user-provided function that can be invoked like a class or object method using ().

Composite

A Parameter that is a composite of a set of other attributes of the class.

+
+
+

Parameter helpers#

+ + + + + + + + + + + + + + + + + + +

get_soft_bounds(bounds, softbounds)

For each soft bound (upper and lower), if there is a defined bound (not equal to None) and does not exceed the hard bound, then it is returned.

guess_bounds(params, **overrides)

Given a dictionary of Parameter instances, return a corresponding set of copies with the bounds appropriately set.

guess_param_types(**kwargs)

Given a set of keyword literals, promote to the appropriate parameter type based on some simple heuristics.

param_union(*parameterizeds[, warn])

Given a set of Parameterized objects, returns a dictionary with the union of all param name,value pairs across them.

ParamOverrides(overridden, dict_[, ...])

A dictionary that returns the attribute of a specified object if that attribute is not present in itself.

+
+
+

.param namespace#

+

These methods and properties are available under the .param namespace +of Parameterized classes and instances.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

add_parameter(param_name, param_obj)

Add a new Parameter object into this object's class.

debug(msg, *args, **kw)

Print msg merged with args as a debugging statement.

defaults()

Return {parameter_name:parameter.default} for all non-constant Parameters.

deserialize_parameters(serialization[, ...])

deserialize_value(pname, value[, mode])

force_new_dynamic_value(name)

Force a new value to be generated for the dynamic attribute name, and return it.

get_param_values([onlychanged])

Return a list of name,value pairs for all Parameters of this object.

get_value_generator(name)

Return the value or value-generating object of the named attribute.

inspect_value(name)

Return the current value of the named attribute without modifying it.

log(level, msg, *args, **kw)

Print msg merged with args as a message at the indicated logging level.

message(msg, *args, **kw)

Print msg merged with args as a message.

method_dependencies(name[, intermediate])

Given the name of a method, returns a PInfo object for each dependency of this method.

objects([instance])

Returns the Parameters of this instance or class

outputs()

Returns a mapping between any declared outputs and a tuple of the declared Parameter type, the output method, and the index into the output if multiple outputs are returned.

params([parameter_name])

Return the Parameters of this class as the dictionary {name: parameter_object}

params_depended_on(*args, **kwargs)

Given the name of a method, returns a PInfo object for each dependency of this method.

pprint([imports, prefix, unknown_value, ...])

(Experimental) Pretty printed representation that may be evaluated with eval.

print_param_defaults()

Print the default values of all cls's Parameters.

print_param_values()

Print the values of all this object's Parameters.

schema([safe, subset, mode])

Returns a schema for the parameters on this Parameterized object.

set_default(param_name, value)

Set the default value of param_name.

set_dynamic_time_fn(time_fn[, sublistattr])

Set time_fn for all Dynamic Parameters of this class or instance object that are currently being dynamically generated.

set_param(*args, **kwargs)

For each param=value keyword argument, sets the corresponding parameter of this object or class to the given value.

serialize_parameters([subset, mode])

serialize_value(pname[, mode])

trigger(*param_names)

Trigger watchers for the given set of parameter names.

unwatch(watcher)

Remove the given Watcher object (from watch or watch_values) from this object's list.

update(*args, **kwargs)

For the given dictionary or iterable or set of param=value keyword arguments, sets the corresponding parameter of this object or class to the given value.

values([onlychanged])

Return a dictionary of name,value pairs for the Parameters of this object.

verbose(msg, *args, **kw)

Print msg merged with args as a verbose message.

warning(msg, *args, **kw)

Print msg merged with args as a warning, unless module variable warnings_as_exceptions is True, then raise an Exception containing the arguments.

watch(fn, parameter_names[, what, ...])

Register the given callback function fn to be invoked for events on the indicated parameters.

watch_values(fn, parameter_names[, what, ...])

Easier-to-use version of watch specific to watching for changes in parameter values.

watchers

Dictionary of instance watchers.

+
+
+

Logging#

+ + + + + + + + + +

param.parameterized.get_logger([name])

param.parameterized.logging_level(level)

Temporarily modify param's logging level.

+
+
+

Serialization#

+

Classes used to support string serialization of Parameters and +Parameterized objects.

+
+
+param.serializer.JSONNullable(json_type)[source]#
+

Express a JSON schema type as nullable to easily support Parameters that allow_None

+
+ +
+
+class param.serializer.JSONSerialization[source]#
+

Class responsible for specifying JSON serialization, deserialization +and JSON schemas for Parameters and Parameterized classes and +objects.

+
+
+classmethod array_schema(p, safe=False)[source]#
+
+ +
+
+classmethod calendardate_schema(p, safe=False)[source]#
+
+ +
+
+classmethod class__schema(class_, safe=False)[source]#
+
+ +
+
+classmethod classselector_schema(p, safe=False)[source]#
+
+ +
+
+classmethod dataframe_schema(p, safe=False)[source]#
+
+ +
+
+classmethod date_schema(p, safe=False)[source]#
+
+ +
+
+classmethod declare_numeric_bounds(schema, bounds, inclusive_bounds)[source]#
+

Given an applicable numeric schema, augment with bounds information

+
+ +
+
+classmethod deserialize_parameter_value(pobj, pname, value)[source]#
+

Deserialize a single parameter value.

+
+ +
+
+classmethod deserialize_parameters(pobj, serialization, subset=None)[source]#
+

Deserialize a serialized object representing one or +more Parameters into a dictionary of parameter values.

+
+ +
+
+classmethod dict_schema(p, safe=False)[source]#
+
+ +
+
+classmethod dumps(obj)[source]#
+
+ +
+
+classmethod integer_schema(p, safe=False)[source]#
+
+ +
+
+json_schema_literal_types = {<class 'int'>: 'integer', <class 'float'>: 'number', <class 'str'>: 'string', <class 'NoneType'>: 'null'}#
+
+ +
+
+classmethod list_schema(p, safe=False)[source]#
+
+ +
+
+classmethod listselector_schema(p, safe=False)[source]#
+
+ +
+
+classmethod loads(serialized)[source]#
+
+ +
+
+classmethod number_schema(p, safe=False)[source]#
+
+ +
+
+classmethod numerictuple_schema(p, safe=False)[source]#
+
+ +
+
+classmethod objectselector_schema(p, safe=False)[source]#
+
+ +
+
+classmethod param_schema(ptype, p, safe=False, subset=None)[source]#
+
+ +
+
+classmethod range_schema(p, safe=False)[source]#
+
+ +
+
+classmethod schema(pobj, safe=False, subset=None)[source]#
+
+ +
+
+classmethod selector_schema(p, safe=False)[source]#
+
+ +
+
+classmethod serialize_parameter_value(pobj, pname)[source]#
+

Serialize a single parameter value.

+
+ +
+
+classmethod serialize_parameters(pobj, subset=None)[source]#
+

Serialize the parameters on a Parameterized object into a +single serialized object, e.g. a JSON string.

+
+ +
+
+classmethod tuple_schema(p, safe=False)[source]#
+
+ +
+
+unserializable_parameter_types = ['Callable']#
+
+ +
+
+classmethod xycoordinates_schema(p, safe=False)[source]#
+
+ +
+ +
+
+class param.serializer.Serialization[source]#
+

Base class used to implement different types of serialization.

+
+
+classmethod deserialize_parameter_value(pobj, pname, value)[source]#
+

Deserialize a single parameter value.

+
+ +
+
+classmethod deserialize_parameters(pobj, serialized, subset=None)[source]#
+

Deserialize a serialized object representing one or +more Parameters into a dictionary of parameter values.

+
+ +
+
+classmethod schema(pobj, subset=None)[source]#
+
+ +
+
+classmethod serialize_parameter_value(pobj, pname)[source]#
+

Serialize a single parameter value.

+
+ +
+
+classmethod serialize_parameters(pobj, subset=None)[source]#
+

Serialize the parameters on a Parameterized object into a +single serialized object, e.g. a JSON string.

+
+ +
+ +
+
+exception param.serializer.UnsafeserializableException[source]#
+
+ +
+
+exception param.serializer.UnserializableException[source]#
+
+ +
+
+
+
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/logging.html b/reference/param/logging.html new file mode 100644 index 0000000..7cbd2e7 --- /dev/null +++ b/reference/param/logging.html @@ -0,0 +1,706 @@ + + + + + + + + + + + + Logging — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + + + + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/param_namespace.html b/reference/param/param_namespace.html new file mode 100644 index 0000000..214637f --- /dev/null +++ b/reference/param/param_namespace.html @@ -0,0 +1,804 @@ + + + + + + + + + + + + .param namespace — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

.param namespace#

+

These methods and properties are available under the .param namespace +of Parameterized classes and instances.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

add_parameter(param_name, param_obj)

Add a new Parameter object into this object's class.

debug(msg, *args, **kw)

Print msg merged with args as a debugging statement.

defaults()

Return {parameter_name:parameter.default} for all non-constant Parameters.

deserialize_parameters(serialization[, ...])

deserialize_value(pname, value[, mode])

force_new_dynamic_value(name)

Force a new value to be generated for the dynamic attribute name, and return it.

get_param_values([onlychanged])

Return a list of name,value pairs for all Parameters of this object.

get_value_generator(name)

Return the value or value-generating object of the named attribute.

inspect_value(name)

Return the current value of the named attribute without modifying it.

log(level, msg, *args, **kw)

Print msg merged with args as a message at the indicated logging level.

message(msg, *args, **kw)

Print msg merged with args as a message.

method_dependencies(name[, intermediate])

Given the name of a method, returns a PInfo object for each dependency of this method.

objects([instance])

Returns the Parameters of this instance or class

outputs()

Returns a mapping between any declared outputs and a tuple of the declared Parameter type, the output method, and the index into the output if multiple outputs are returned.

params([parameter_name])

Return the Parameters of this class as the dictionary {name: parameter_object}

params_depended_on(*args, **kwargs)

Given the name of a method, returns a PInfo object for each dependency of this method.

pprint([imports, prefix, unknown_value, ...])

(Experimental) Pretty printed representation that may be evaluated with eval.

print_param_defaults()

Print the default values of all cls's Parameters.

print_param_values()

Print the values of all this object's Parameters.

schema([safe, subset, mode])

Returns a schema for the parameters on this Parameterized object.

set_default(param_name, value)

Set the default value of param_name.

set_dynamic_time_fn(time_fn[, sublistattr])

Set time_fn for all Dynamic Parameters of this class or instance object that are currently being dynamically generated.

set_param(*args, **kwargs)

For each param=value keyword argument, sets the corresponding parameter of this object or class to the given value.

serialize_parameters([subset, mode])

serialize_value(pname[, mode])

trigger(*param_names)

Trigger watchers for the given set of parameter names.

unwatch(watcher)

Remove the given Watcher object (from watch or watch_values) from this object's list.

update(*args, **kwargs)

For the given dictionary or iterable or set of param=value keyword arguments, sets the corresponding parameter of this object or class to the given value.

values([onlychanged])

Return a dictionary of name,value pairs for the Parameters of this object.

verbose(msg, *args, **kw)

Print msg merged with args as a verbose message.

warning(msg, *args, **kw)

Print msg merged with args as a warning, unless module variable warnings_as_exceptions is True, then raise an Exception containing the arguments.

watch(fn, parameter_names[, what, ...])

Register the given callback function fn to be invoked for events on the indicated parameters.

watch_values(fn, parameter_names[, what, ...])

Easier-to-use version of watch specific to watching for changes in parameter values.

watchers

Dictionary of instance watchers.

+
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/parameter_helpers.html b/reference/param/parameter_helpers.html new file mode 100644 index 0000000..c42b4dc --- /dev/null +++ b/reference/param/parameter_helpers.html @@ -0,0 +1,715 @@ + + + + + + + + + + + + Parameter helpers — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

Parameter helpers#

+ + + + + + + + + + + + + + + + + + +

get_soft_bounds(bounds, softbounds)

For each soft bound (upper and lower), if there is a defined bound (not equal to None) and does not exceed the hard bound, then it is returned.

guess_bounds(params, **overrides)

Given a dictionary of Parameter instances, return a corresponding set of copies with the bounds appropriately set.

guess_param_types(**kwargs)

Given a set of keyword literals, promote to the appropriate parameter type based on some simple heuristics.

param_union(*parameterizeds[, warn])

Given a set of Parameterized objects, returns a dictionary with the union of all param name,value pairs across them.

ParamOverrides(overridden, dict_[, ...])

A dictionary that returns the attribute of a specified object if that attribute is not present in itself.

+
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/parameterized_helpers.html b/reference/param/parameterized_helpers.html new file mode 100644 index 0000000..d06cc5c --- /dev/null +++ b/reference/param/parameterized_helpers.html @@ -0,0 +1,730 @@ + + + + + + + + + + + + Parameterized helpers — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

Parameterized helpers#

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

param.parameterized.Event(what, name, obj, ...)

Object representing an event that triggers a Watcher.

param.parameterized.Watcher(*args, **kwargs)

Object declaring a callback function to invoke when an Event is triggered on a watched item.

batch_watch(parameterized[, enable, run])

param.parameterized.batch_call_watchers(...)

Context manager to batch events to provide to Watchers on a parameterized object.

concrete_descendents(parentclass)

Return a dictionary containing all subclasses of the specified parentclass, including the parentclass.

depends(func, *dependencies[, watch, on_init])

Annotates a function or Parameterized method to express its dependencies.

discard_events(parameterized)

Context manager that discards any events within its scope triggered on the supplied parameterized object.

edit_constant(parameterized)

Temporarily set parameters on Parameterized object to constant=False to allow editing them.

output(func, *output, **kw)

output allows annotating a method on a Parameterized class to declare that it returns an output of a specific type.

script_repr(val[, imports, prefix, ...])

Variant of pprint() designed for generating a (nearly) runnable script.

+
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/parameterized_objects.html b/reference/param/parameterized_objects.html new file mode 100644 index 0000000..84e58dc --- /dev/null +++ b/reference/param/parameterized_objects.html @@ -0,0 +1,706 @@ + + + + + + + + + + + + Parameterized objects — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

Parameterized objects#

+ + + + + + + + + +

Parameterized

Base class for named objects that support Parameters and message formatting.

ParameterizedFunction

Acts like a Python function, but with arguments that are Parameters.

+
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/parameters.html b/reference/param/parameters.html new file mode 100644 index 0000000..987c4e1 --- /dev/null +++ b/reference/param/parameters.html @@ -0,0 +1,802 @@ + + + + + + + + + + + + Parameters — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

Parameters#

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Parameter

An attribute descriptor for declaring parameters.

String

A String Parameter, with a default value and optional regular expression (regex) matching.

Bytes

A Bytes Parameter, with a default value and optional regular expression (regex) matching.

Color

Color parameter defined as a hex RGB string with an optional # prefix or (optionally) as a CSS3 color name.

Boolean

Binary or tristate Boolean Parameter.

Event

An Event Parameter is one whose value is intimately linked to the triggering of events for watchers to consume.

Dynamic

Parameter whose value can be generated dynamically by a callable object.

Number

A numeric Dynamic Parameter, with a default value and optional bounds.

Integer

Numeric Parameter required to be an Integer

Magnitude

Numeric Parameter required to be in the range [0.0-1.0].

Tuple

A tuple Parameter (e.g.

NumericTuple

A numeric tuple Parameter (e.g.

XYCoordinates

A NumericTuple for an X,Y coordinate.

Range

A numeric range with optional bounds and softbounds.

DateRange

A datetime or date range specified as (start, end).

CalendarDateRange

A date range specified as (start_date, end_date).

List

Parameter whose value is a list of objects, usually of a specified type.

HookList

Parameter whose value is a list of callable objects.

Path

Parameter that can be set to a string specifying the path of a file or folder.

Filename

Parameter that can be set to a string specifying the path of a file.

Foldername

Parameter that can be set to a string specifying the path of a folder.

CalendarDateRange

A date range specified as (start_date, end_date).

Selector

Parameter whose value must be one object from a list of possible objects.

FileSelector

Given a path glob, allows one file to be selected from those matching.

ListSelector

Variant of Selector where the value can be multiple objects from a list of possible objects.

MultiFileSelector

Given a path glob, allows multiple files to be selected from the list of matches.

ClassSelector

Parameter allowing selection of either a subclass or an instance of a given set of classes.

Dict

Parameter whose value is a dictionary.

Array

Parameter whose value is a numpy array.

Series

Parameter whose value is a pandas Series.

DataFrame

Parameter whose value is a pandas DataFrame.

Callable

Parameter holding a value that is a callable object, such as a function.

Action

A user-provided function that can be invoked like a class or object method using ().

Composite

A Parameter that is a composite of a set of other attributes of the class.

+
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/reference/param/serialization.html b/reference/param/serialization.html new file mode 100644 index 0000000..3233e96 --- /dev/null +++ b/reference/param/serialization.html @@ -0,0 +1,957 @@ + + + + + + + + + + + + Serialization — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

Serialization#

+

Classes used to support string serialization of Parameters and +Parameterized objects.

+
+
+param.serializer.JSONNullable(json_type)[source]#
+

Express a JSON schema type as nullable to easily support Parameters that allow_None

+
+ +
+
+class param.serializer.JSONSerialization[source]#
+

Class responsible for specifying JSON serialization, deserialization +and JSON schemas for Parameters and Parameterized classes and +objects.

+
+
+classmethod array_schema(p, safe=False)[source]#
+
+ +
+
+classmethod calendardate_schema(p, safe=False)[source]#
+
+ +
+
+classmethod class__schema(class_, safe=False)[source]#
+
+ +
+
+classmethod classselector_schema(p, safe=False)[source]#
+
+ +
+
+classmethod dataframe_schema(p, safe=False)[source]#
+
+ +
+
+classmethod date_schema(p, safe=False)[source]#
+
+ +
+
+classmethod declare_numeric_bounds(schema, bounds, inclusive_bounds)[source]#
+

Given an applicable numeric schema, augment with bounds information

+
+ +
+
+classmethod deserialize_parameter_value(pobj, pname, value)[source]#
+

Deserialize a single parameter value.

+
+ +
+
+classmethod deserialize_parameters(pobj, serialization, subset=None)[source]#
+

Deserialize a serialized object representing one or +more Parameters into a dictionary of parameter values.

+
+ +
+
+classmethod dict_schema(p, safe=False)[source]#
+
+ +
+
+classmethod dumps(obj)[source]#
+
+ +
+
+classmethod integer_schema(p, safe=False)[source]#
+
+ +
+
+json_schema_literal_types = {<class 'int'>: 'integer', <class 'float'>: 'number', <class 'str'>: 'string', <class 'NoneType'>: 'null'}#
+
+ +
+
+classmethod list_schema(p, safe=False)[source]#
+
+ +
+
+classmethod listselector_schema(p, safe=False)[source]#
+
+ +
+
+classmethod loads(serialized)[source]#
+
+ +
+
+classmethod number_schema(p, safe=False)[source]#
+
+ +
+
+classmethod numerictuple_schema(p, safe=False)[source]#
+
+ +
+
+classmethod objectselector_schema(p, safe=False)[source]#
+
+ +
+
+classmethod param_schema(ptype, p, safe=False, subset=None)[source]#
+
+ +
+
+classmethod range_schema(p, safe=False)[source]#
+
+ +
+
+classmethod schema(pobj, safe=False, subset=None)[source]#
+
+ +
+
+classmethod selector_schema(p, safe=False)[source]#
+
+ +
+
+classmethod serialize_parameter_value(pobj, pname)[source]#
+

Serialize a single parameter value.

+
+ +
+
+classmethod serialize_parameters(pobj, subset=None)[source]#
+

Serialize the parameters on a Parameterized object into a +single serialized object, e.g. a JSON string.

+
+ +
+
+classmethod tuple_schema(p, safe=False)[source]#
+
+ +
+
+unserializable_parameter_types = ['Callable']#
+
+ +
+
+classmethod xycoordinates_schema(p, safe=False)[source]#
+
+ +
+ +
+
+class param.serializer.Serialization[source]#
+

Base class used to implement different types of serialization.

+
+
+classmethod deserialize_parameter_value(pobj, pname, value)[source]#
+

Deserialize a single parameter value.

+
+ +
+
+classmethod deserialize_parameters(pobj, serialized, subset=None)[source]#
+

Deserialize a serialized object representing one or +more Parameters into a dictionary of parameter values.

+
+ +
+
+classmethod schema(pobj, subset=None)[source]#
+
+ +
+
+classmethod serialize_parameter_value(pobj, pname)[source]#
+

Serialize a single parameter value.

+
+ +
+
+classmethod serialize_parameters(pobj, subset=None)[source]#
+

Serialize the parameters on a Parameterized object into a +single serialized object, e.g. a JSON string.

+
+ +
+ +
+
+exception param.serializer.UnsafeserializableException[source]#
+
+ +
+
+exception param.serializer.UnserializableException[source]#
+
+ +
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/releases.html b/releases.html new file mode 100644 index 0000000..e50cda7 --- /dev/null +++ b/releases.html @@ -0,0 +1,1205 @@ + + + + + + + + + + + + Releases — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

Releases#

+
+

Version 1.13.0#

+

Date: 2023-03-14

+

The 1.13.0 is the last release of Param before the 2.0 release. However, Param 1.13 is meant to receive long-term support; security patches and fixes to critical bugs are planned to be backported to the 1.13.x series.

+

This release includes a new Bytes Parameter and a few important bug fixes. This release is also marked by the adoption of a formal project governance, ensuring Param’s future as a healthy open-source project. Many thanks to @ovidner and @droumis for their first contributions! And to @maximlt, @Hoxbro, @jlstevens, @philippjfr and @jbednar for their continuing support to fixing and improving Param.

+

Bug fixes:

+
    +
  • Fix copying when having watchers on e.g. bounds on inherited Parameter types (#675)

  • +
  • Allow JSON serialization to work with json.dumps (#655)

  • +
  • ListSelector restricted to list type objects (#531)

  • +
  • Fix depends async wrapper (#684)

  • +
  • Allow named colors to be any case (#711)

  • +
+

New features:

+
    +
  • Add Bytes parameter (#542)

  • +
+

Documentation:

+
    +
  • Fix param module link (#682)

  • +
+

Project governance:

+
    +
  • Create initial project governance docs (#674)

  • +
+

Maintenance:

+
    +
  • Rename master branch to main (#672)

  • +
  • Add more tests (#710)

  • +
  • Various CI related fixes (#680, #683 and #709)

  • +
+
+
+

Version 1.12.3#

+

Date: 2022-12-06

+

The 1.12.3 release adds support for Python 3.11. Many thanks to @musicinmybrain (first contribution!) and @maximlt for contributing to this release.

+

Enhancements:

+
    +
  • Preserve existing Random seed behavior in Python 3.11 (#638)

  • +
  • Add support for Python 3.11 (#658)

  • +
+
+
+

Version 1.12.2#

+

Date: 2022-06-14

+

The 1.12.2 release fixes a number of bugs and adds support again for Python 2.7, which was unfortunately no longer supported in the last release. Note however that Param 2.0 will still drop support of Python 2.7 as already announced. Many thanks to @Hoxbro and the maintainers @jbednar, @jlstevens, @maximlt and @philippjfr for contributing to this release.

+

Bug fixes:

+
    +
  • Match against complete spec name when determining dynamic watchers (#615)

  • +
  • Ensure async functionality does not cause python2 syntax errors (#624)

  • +
  • Allow (de)serializing CalendarRange and DateRange Parameters (#625)

  • +
  • Improve DateRange validation (#627)

  • +
  • Fix regression in @param.depends execution ordering (#628)

  • +
  • Ensure named_objs does not fail on unhashable objects (#632)

  • +
  • Support comparing date-like objects (#629)

  • +
  • Fixed BinaryPower example in the docs to use the correct name EvenInteger(#634)

  • +
+
+
+

Version 1.12.1#

+

The 1.12.1 release fixes a number of bugs related to async callback handling when using param.depends and .param.watch and a number of documentation and error messages. Many thanks to @HoxBro and the maintainers @jbednar, @jlstevens, @maximlt and @philippjfr for contributing to this release.

+

Error handling and documentation:

+
    +
  • Fixed description of shared_parameters (#568)

  • +
  • Improve the error messages of Date and DateRange (#579)

  • +
  • Clarified step error messages and other docs and links (#604)

  • +
+

Bug fixes:

+
    +
  • Make iscoroutinefunction more robust (#572)

  • +
  • Fix for handling misspelled parameter (#575)

  • +
  • Handle None serialization for Date, CalendarDate, Tuple, Array, and DataFrame (#582)

  • +
  • Support async coroutines in param.depends (#591)

  • +
  • Handle async functions in depends with watch=True (#611)

  • +
  • Avoid equality check on Watcher (#612)

  • +
+

Documentation:

+
    +
  • Fix binder (#564)

  • +
  • Fixed description of shared_parameters (#568)

  • +
+
+
+

Version 1.12.0#

+

Version 1.12.0 introduces a complete user manual and website (for the first time since 2003!) along with extensive API improvements gearing up for the 2.0 release (which will be Python3 only).

+

The pre-2.0 API is still being preserved and no new warnings are added in this release, so the older API can continue to be used with this release, but the next 1.x release is expected to enable warnings for deprecated API. If you have older code using the deprecated Param features below, please update your API calls as described below to be compatible with the 2.0 release when it comes out (or pin to param<2 if you don’t need any new Param features). For new users, just use the API documented on the website, and you should be ready to go for either 1.12+ or 2.0+.

+

Thanks to James A. Bednar for the user guide and 2.0 API support, to Philipp Rudiger for improvements and new capabilities for handling dependencies on subobjects, and to Maxime Liquet and Philipp Rudiger for extensive improvements to the website/docs/package-building/testing.

+

New features:

+
    +
  • Added future-facing API for certain Parameterized().param methods (see Compatibility below; #556, #558, #559)

  • +
  • New option on_init=True for @depends decorator, to run the method in the constructor to ensure initial state is consistent when appropriate (#540)

  • +
  • Now resolves subobject dependencies dynamically, allowing dependencies on internal parameters of subobjects to resolve appropriately as those objects are replaced. (#552)

  • +
  • Added prettyprinting for numbergen expressions (#525)

  • +
  • Improved JSON schema generation (#458)

  • +
  • Added more-usable script_repr command, availabie in param namespace, with default values, and showing imports (#522)

  • +
  • Added Parameterized.param.pprint(); underlying implementation of script_repr but with defaults suitable for interactive usage rather than generating a .py script. (#522)

  • +
  • Watchers can now declare precedence so that events are triggered in the desired order (#552, #557)

  • +
+

Bug fixes:

+
    +
  • Fix bug setting attributes in some cases before class is initialized (#544)

  • +
  • Ensure None is supported on ListSelector (#511)

  • +
  • Switched from deprecated inspect.getargspec to the py3 version inspect.getfullargspec, which is similar but splits keyword args into varkw (**) and kw-only args. Falls back to getargspec on Python2. (#521)

  • +
+

Doc improvements (including complete user guide for the first time!):

+
    +
  • Misc comments/docstrings/docs cleanup (#507, #518, #528, #553)

  • +
  • Added comparison with pydantic (#523)

  • +
  • Added new user guide sections:

    +
      +
    • Dependencies_and_Watchers user guide (#536)

    • +
    • Dynamic Parameters (#525)

    • +
    • Outputs (#523)

    • +
    • Serialization and Persistence (#523)

    • +
    +
  • +
+

Infrastructure:

+ +

Compatibility (see #543 for the complete list):

+
    +
  • Calendardate now accepts date values only (#517)

  • +
  • No longer allows modifying name of a Parameter once it is in a Parameterized class, to avoid confusion (#541)

  • +
  • Renamed (with old name still accepted for compatibility until 2.0):

    +
      +
    • .param._add_parameter(): Now public .param.add_parameter(); too useful to keep private! (#559)

    • +
    • .param.params_depended_on: Now .param.method_dependencies to indicate that it accepts a method name and returns its dependencies (#559)

    • +
    • .pprint: Now private ._pprint; use public .param.pprint instead (#559)

    • +
    • batch_watch: Now batch_call_watchers, to declare that it does not set up watching, it just invokes it. Removed unused operation argument (#536)

    • +
    +
  • +
  • Deprecated (but not yet warning unless noted):

    +
      +
    • .param.debug(): Use .param.log(param.DEBUG, ...) instead (#556)

    • +
    • .param.verbose(): Use .param.log(param.VERBOSE, ...) instead (#556)

    • +
    • .param.message(): Use .param.log(param.MESSAGE, ...) instead (#556)

    • +
    • .param.defaults(): Use {k:v.default for k,v in p.param.objects().items()} instead (#559)

    • +
    • .param.deprecate(): To be repurposed or deleted after 2.0 (#559)

    • +
    • .param.params(): Use .param.values() or .param['param'] instead (#559)

    • +
    • .param.print_param_defaults(): Use for k,v in p.param.objects().items(): print(f"{p.__class__.name}.{k}={repr(v.default)}") instead (#559)

    • +
    • .param.print_param_values(): Use for k,v in p.param.values().items(): print(f"{p.name}.{k}={v}") instead (#559)

    • +
    • .param.set_default(): Use p.param.default= instead (#559)

    • +
    • .param.set_param(): Had tricky API; use .param.update instead (#558)

    • +
    • .param.get_param_values(): Use .param.values().items() instead (or .param.values() for the common case of dict(....param.get_param_values())) (#559)

    • +
    • .state_pop(): Will be renamed to ._state_pop to make private

    • +
    • .state_push(): Will be renamed to ._state_push to make private

    • +
    • .initialized: Will be renamed to ._initialized to make private

    • +
    • Most methods on Parameterized itself have already been deprecated and warning for some time now; see #543 for the list. Use the corresponding method on the .param accessor instead.

    • +
    +
  • +
  • Added:

    +
      +
    • .param.watchers: Read-only version of private _watchers (#559)

    • +
    • .param.log(): Subsumes .debug/verbose/message; all are logging calls. (#556)

    • +
    • .param.update(): Dictionary-style updates to parameter values, as a drop-in replacement for set_param except for its optional legacy positional-arg syntax (#558)

    • +
    • .values(): Dictionary of name:value pairs for parameter values, replacing get_param_values but now a dict since python3 preserves order (#558)

    • +
    • .param.log(): General-purpose interface to the logging module functionailty; replaces .debug, .verbose, .message (#556)

    • +
    +
  • +
+
+
+

Version 1.11.1#

+

(including changes in 1.11.0; 1.11.1 adds only a minor change to fix param.List(None).)

+

Version 1.11 contains entirely new documentation, plus various enhancements and bugfixess. Thanks to James A. Bednar for the documentation, Philipp Rudiger for the website setup and for many of the other fixes and improvements below, and others as noted below.

+

Documentation:

+
    +
  • Brand-new website, with getting started, user manual, reference manual, and more! Some user guide sections are still under construction. (#428,#464,#479,#483,#501,#502,#503,#504)

  • +
  • New intro video with examples/Promo.ipynb notebook, thanks to Marc Skov Madsen and Egbert Ammicht (#488)

  • +
  • Sort docstring by definition order and precedence, thanks to Andrew Huang (#445)

  • +
+

Enhancements:

+
    +
  • Allow printing representations for recursively nested Parameterized objects (#499)

  • +
  • Allow named colors for param.Color (#472)

  • +
  • Allow FileSelector and MultiFileSelector to accept initial values (#497)

  • +
  • Add Step slot to Range, thanks to Simon Hansen (#467)

  • +
  • Update FileSelector and MultiFileSelector parameters when setting path (#476)

  • +
  • Improved error messages (#475)

  • +
+

Bug Fixes:

+
    +
  • Fix Path to allow folders, as documented but previously not supported (#495)

  • +
  • Fix previously unimplemented Parameter._on_set (#484)

  • +
  • Fix Python2 IPython output parameter precedence (#477)

  • +
  • Fix allow_None for param.Series and param.DataFrame (#473)

  • +
  • Fix behavior when both instantiate and constant are True (#474)

  • +
  • Fix for versioning when param is inside a separate git-controlled repo (port of fix from autover/pull/67) (#469)

  • +
+

Compatibility:

+
    +
  • Swapped ObjectSelector and Selector in the inheritance hierarchy, to allow ObjectSelector to be deprecated. (#497)

  • +
  • Now get_soft_boundssilently crops softbounds to any hard bounds supplied ; previously soft bounds would be returned even if they were outside the hard bounds (#498)

  • +
  • Rename class_ to item_type in List parameter, to avoid clashing semantics with ClassSelector and others with a class_ slot. class_ is still accepted as a keyword but is stored in item_type. (#456)

  • +
+
+
+

Version 1.10.1#

+

Minor release for Panel-related bugfixes and minor features, from @philippjfr.

+
    +
  • Fix serialization of Tuple, for use in Panel (#446)

  • +
  • Declare asynchronous executor for Panel to use (#449)

  • +
  • Switch to GitHub Actions (#450)

  • +
+
+
+

Version 1.10.0#

+
+
+

Version 1.9.3#

+
    +
  • Fixed ClassSelector.get_range when a tuple of types is supplied (#360)

  • +
+
+
+

Version 1.9.2#

+
    +
  • Compatibility with Python 3.8

  • +
  • Add eager option to watch calls (#351)

  • +
  • Add Calendar and CalendarDateRange for real date types (#348)

  • +
+
+
+

Version 1.9.1#

+

Enhancements:

+
    +
  • Allow param.depends to annotate functions (#334)

  • +
  • Add context managers to manage events and edit constant parameters

  • +
+

Bug fixes:

+
    +
  • Ensure that Select constructor does not rely on truthiness (#337)

  • +
  • Ensure that param.depends allows mixed Parameter types (#338)

  • +
  • Date and DateRange now allow dt.date type (#341)

  • +
  • Ensure events aren’t dropped in batched mode (#343)

  • +
+
+
+

Version 1.9.0#

+

Full release with new functionality and some fixes. New features:

+
    +
  • Added support for instance parameters, allowing parameter metadata to be modified per instance and allowing parameter objects to be passed to Panel objects (#306)

  • +
  • Added label slot to Parameter, to allow overriding attribute name for display (#319)

  • +
  • Added step slot to Parameter, e.g. to control Panel widget step size (#326)

  • +
  • Added keywords_to_params utility for deducing Parameter types and ranges automatically (#317)

  • +
  • Added support for multiple outputs from a Parameterized (#312)

  • +
  • Added Selector as a more user-friendly version of ObjectSelector, accepting a list of options as a positional argument (#316)

  • +
+

Changes affecting backwards compatibility:

+
    +
  • Changed from root logger to a param-specific logger; no change to API but will change format of error and warning messages (#330)

  • +
  • Old abstract class Selector renamed to SelectorBase; should be no change unless user code added custom classes inherited from Selector without providing a constructor (#316)

  • +
+

Bugfixes and other improvements:

+ +

For more details, you can see a full list of changes since the previous release.

+
+
+

Version 1.8.2#

+

Minor release:

+
    +
  • Added output decorator and outputs lookup method (#299, #312)

  • +
+

For more details, you can see a full list of changes since the previous release.

+
+
+

Version 1.8.1#

+

Minor release:

+
    +
  • Added positional default arguments for nearly all Parameter subclasses (apart from ClassSelector)

  • +
  • Minor bugfixes for watching callbacks

  • +
+

For more details, you can see a full list of changes since the previous release.

+
+
+

Version 1.8.0#

+

Major new feature set: comprehensive support for events, watching, callbacks, and dependencies

+
    +
  • Parameterized methods can now declare @depends(p,q) to indicate that they depend on parameters p and q (defaulting to all parameters)

  • +
  • Parameterized methods can depend on subobjects with @depends(p.param,q.param.r), where p.param indicates dependencies on all parameters of p and q.param.r indicates a dependency on parameter r of q.

  • +
  • Functions and methods can watch parameter values, re-running when those values change or when an explicit trigger is issued, and can unwatch them later if needed.

  • +
  • Multiple events can be batched to trigger callbacks only once for a coordinated set of changes

  • +
+

Other new features:

+
    +
  • Added support in ObjectSelector for selecting lists and dicts (#268)

  • +
  • Added pandas DataFrame and Series parameter types (#285)

  • +
  • Added support for regular expression validation to String Parameter (#241, #245)

  • +
+

For more details, you can see a full list of changes since the previous release.

+
+
+

Version 1.7.0#

+

Since the previous release (1.6.1), there should be no changes that affect existing code, only additions:

+
    +
  • A new param namespace object, which in future will allow subclasses of Parameterized to have much cleaner namespaces (#230).

  • +
  • Started testing on python 3.7-dev (#223).

  • +
  • param.version now provides functions to simplify dependants’ setup.py/setup.cfg files (see https://github.com/holoviz-dev/autover/pull/49).

  • +
+

Although param should still work on python 3.3, we are no longer testing against it (unsupported by our test environment; #234).

+

For more details, you can see a full list of changes since the previous release.

+
+
+

Version 1.6.1#

+

Restores support for the previous versioning system (pre 1.6; see #225), and fixes a number of issues with the new versioning system:

+
    +
  • Allow package name to differ from repository name (https://github.com/holoviz-dev/autover/pull/39)

  • +
  • Allow develop install to work when repository is dirty (https://github.com/holoviz-dev/autover/pull/41)

  • +
  • Fixed failure to report dirty when commit count is 0 (https://github.com/holoviz-dev/autover/pull/44)

  • +
+
+
+

Version 1.6.0#

+

Notable changes, fixes, and additions since the previous release (1.5.1) are listed below. You can also see a full list of changes since the previous release.

+

Changes:

+
    +
  • param.__version__ is now a string

  • +
  • param.version.Version now supports a tag-based versioning workflow; if using the Version class, you will need to update your workflow (see autover for more details).

  • +
  • Dropped support for python 2.6 (#175).

  • +
  • No longer attempt to cythonize param during installation via pip (#166, #194).

  • +
+

Fixes:

+
    +
  • Allow get_param_values() to work on class (#162).

  • +
  • Fixed incorrect default value for param.Integer (#151).

  • +
  • Allow a String to be None if its default is None (#104).

  • +
  • Fixed ListSelector.compute_default() (#212).

  • +
  • Fixed checks for None in various Parameter subclasses (#208); fixes problems for subclasses of Parameterized that define a custom __nonzero__ or __len__.

  • +
+

Additions:

+
    +
  • Added DateRange parameter.

  • +
+

Miscellaneous:

+
    +
  • No longer tested on python 3.2 (unsupported by our test environment; #218).

  • +
+
+
+

Version 1.5.1#

+
    +
  • Fixed error messages for ClassSelector with tuple of classes

  • +
  • Added get and contains methods for ParamOverrides

  • +
+

A full list of changes since the previous release is available here.

+
+
+

Version 1.5.0#

+
    +
  • Added Range, Color, and Date parameters

  • +
  • Improved ObjectSelector error messages

  • +
  • Minor bugfixes

  • +
+

A full list of changes since the previous release is available here.

+
+
+

Version 1.4.2#

+
    +
  • Improved version reporting from version module

  • +
  • Minor bugfixes

  • +
+

A full list of changes since the previous release is available here.

+
+
+

Version 1.4.1#

+
    +
  • Selector parameters now respect order of options supplied

  • +
  • Allowed softbounds to be accessed like an attribute

  • +
+

A full list of changes since the previous release is available +on GitHub.

+
+
+

Version 1.4.0 (2016/07)#

+
    +
  • Added support for new ParamNB project

  • +
  • Added new parameter types Action, FileSelector, and ListSelector

  • +
+

A full list of changes since the previous release is available +on GitHub.

+
+
+

Version 1.3.2 (2015/04)#

+
    +
  • Added Unicode support for param.String.

  • +
  • Minor bugfixes.

  • +
+

A full list of changes since the previous release is available +on GitHub.

+
+
+

Version 1.3.1 (2015/03)#

+
    +
  • Minor bugfix release to restore pre-1.3.0 script_repr behavior +(accidentally changed in 1.3.0) and to fix issues with logging.

  • +
  • Param’s logging interface now matches that of Python’s logging +module, making it simpler to use logging (see Python’s logging +module for details). Note therefore that Param’s logging methods (a) +no longer call functions that are passed as arguments (instead, +Python’s logging module does lazy string merges), and (b) no longer +automatically combine strings passed as arguments (instead, Python’s +logging module supports string formatting).

  • +
  • Improved set_param() method, now allowing multiple parameters to be +set easily via keyword arguments (as on initialization).

  • +
+

A full list of changes since the previous release is available +on GitHub.

+
+
+

Version 1.3.0 (2015/03)#

+
    +
  • Added ‘allow_None’ support to all Parameters. Any subclass of +Parameter that checks types and/or values should be modified to add +appropriate handling of allow_None.

  • +
  • Improved pretty printing (script_repr) of Parameterized instances, +and made available via the pprint method. The script_repr name will +be removed in a future release.

  • +
  • Added (reproducible) time-dependent random streams +(numbergen.TimeAwareRandomState).

  • +
  • Added label and unit parameters to param.Time class.

  • +
  • Improved optional IPython extension.

  • +
+

A full list of changes since the previous release is available +on GitHub.

+
+
+

Version 1.2.1 (2014/06)#

+
    +
  • Minor bugfix release to fix issues with version when param is +installed in a foreign git repository

  • +
  • Made version module optional

  • +
  • Improved ClassSelector and ParamOverrides

  • +
+

A full list of changes since the previous release is available +on GitHub.

+
+
+

Version 1.2.0 (2014/06)#

+
    +
  • Added support for Python 3 (thanks to Marco Elver).

  • +
  • Dropped support for Python 2.5.

  • +
  • Added version module.

  • +
  • Added optional numbergen package.

  • +
+

A full list of changes since the previous release is available +on GitHub.

+
+
+

Version 1.1.0 (2014/05)#

+
    +
  • Switched to Python’s own logging module.

  • +
  • Improved support for time when using Dynamic parameters.

  • +
  • Optional extension for IPython users.

  • +
+

A full list of changes since the previous release is available +on GitHub.

+
+
+

Version 1.0.0 (2012/07)#

+
    +
  • First standalone release.

  • +
+
+
+

Pre-1.0 (2003)#

+
    +
  • Param was originally developed as part of Topographica, and has been in heavy usage as part of that project since 2003.

  • +
+
+
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/roadmap.html b/roadmap.html new file mode 100644 index 0000000..cad4b2e --- /dev/null +++ b/roadmap.html @@ -0,0 +1,706 @@ + + + + + + + + + + + + Roadmap — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

Roadmap#

+

Param is a mature library (originally from 2003) that changes very slowly and very rarely; it is fully ready for use in production applications. Major changes are undertaken only after significant discussions and with attention to how existing Param-based applications will be affected. Thus Param users should not expect only slow progress on these roadmap items, but they are listed here in the hopes that they will be useful.

+

Currently scheduled plans:

+
    +
  • Remove deprecated API and tag release 2.0. Deprecated API is noted in the source code and except in very rare cases has never been documented on the website, so removing these methods should only affect users of Param from 2020 or earlier.

  • +
  • More powerful serialization (to JSON, YAML, and URLs) to make it simpler to persist the state of a Parameterized object. Some support already merged as https://github.com/holoviz/param/pull/414 , but still to be further developed as support for using Parameterized objects to build REST APIS (see https://github.com/holoviz/lumen for example usage).

  • +
+

Other items that are not yet scheduled but would be great to have:

+
    +
  • Integrate more fully with Python 3 language features like type annotations and data classes, e.g. to respect and validate against declared types without requiring an explicit param.Parameter declaration and potentially without inheriting from param.Parameterized, and to better support IDE type-checking features.

  • +
  • Integrate and interoperate more fully with other frameworks like Django models, Traitlets, attrs, Django models, Pydantic, or swagger/OpenAPI, each of which capture or can use similar information about parameter names, values, and constraints and so in many cases can easily be converted from one to the other.

  • +
  • Improve support for Param in editors, automatic formatting tools, linters, document generators, and other tools that process Python code and could be made to have special-purpose optimizations specifically for Parameterized objects.

  • +
  • Follow PEP8 more strictly: PEP8 definitely wasn’t written with Parameters in mind, and it typically results in badly formatted files when applied to Parameterized code. But PEP8 could be applied to Param’s own code, e.g. using Black.

  • +
  • Triaging open issues: The Param developer team consists of volunteers typically using Param on their projects but not explicity tasked with or funded to work on Param itself. It would thus be great if the more experienced Param users could help address some of the issues that have been raised but not yet solved.

  • +
  • Improve test coverage

  • +
+

Other issues are collected on Github and will be addressed on various time scales as indicated by the issue’s milestone (typically next minor release, next major release, or “wishlist” (not scheduled or assigned to any person but agreed to be desirable). Any contributor is encouraged to attempt to implement a “wishlist” item, though if it is particularly complex or time consuming it is useful to discuss it first with one of the core maintainers (e.g. by stating your intentions on the issue).

+
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/search.html b/search.html new file mode 100644 index 0000000..399e32e --- /dev/null +++ b/search.html @@ -0,0 +1,654 @@ + + + + + + + + + + Search - param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+ + +
+

Search

+ + + +
+
+ + + + +
+ +
+ +
+
+
+ +
+ +
+ +
+ + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/searchindex.js b/searchindex.js new file mode 100644 index 0000000..38dc306 --- /dev/null +++ b/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({"docnames": ["about", "comparisons", "developer_guide", "getting_started", "index", "reference/index", "reference/numbergen", "reference/param/generated/param.Action", "reference/param/generated/param.Array", "reference/param/generated/param.Boolean", "reference/param/generated/param.Bytes", "reference/param/generated/param.CalendarDateRange", "reference/param/generated/param.Callable", "reference/param/generated/param.ClassSelector", "reference/param/generated/param.Color", "reference/param/generated/param.Composite", "reference/param/generated/param.DataFrame", "reference/param/generated/param.DateRange", "reference/param/generated/param.Dict", "reference/param/generated/param.Dynamic", "reference/param/generated/param.Event", "reference/param/generated/param.FileSelector", "reference/param/generated/param.Filename", "reference/param/generated/param.Foldername", "reference/param/generated/param.HookList", "reference/param/generated/param.Integer", "reference/param/generated/param.List", "reference/param/generated/param.ListSelector", "reference/param/generated/param.Magnitude", "reference/param/generated/param.MultiFileSelector", "reference/param/generated/param.Number", "reference/param/generated/param.NumericTuple", "reference/param/generated/param.ParamOverrides", "reference/param/generated/param.Parameter", "reference/param/generated/param.Parameterized", "reference/param/generated/param.ParameterizedFunction", "reference/param/generated/param.Path", "reference/param/generated/param.Range", "reference/param/generated/param.Selector", "reference/param/generated/param.Series", "reference/param/generated/param.String", "reference/param/generated/param.Tuple", "reference/param/generated/param.XYCoordinates", "reference/param/generated/param.batch_watch", "reference/param/generated/param.concrete_descendents", "reference/param/generated/param.depends", "reference/param/generated/param.discard_events", "reference/param/generated/param.edit_constant", "reference/param/generated/param.get_soft_bounds", "reference/param/generated/param.guess_bounds", "reference/param/generated/param.guess_param_types", "reference/param/generated/param.output", "reference/param/generated/param.param_union", "reference/param/generated/param.parameterized.Event", "reference/param/generated/param.parameterized.Parameters.add_parameter", "reference/param/generated/param.parameterized.Parameters.debug", "reference/param/generated/param.parameterized.Parameters.defaults", "reference/param/generated/param.parameterized.Parameters.deserialize_parameters", "reference/param/generated/param.parameterized.Parameters.deserialize_value", "reference/param/generated/param.parameterized.Parameters.force_new_dynamic_value", "reference/param/generated/param.parameterized.Parameters.get_param_values", "reference/param/generated/param.parameterized.Parameters.get_value_generator", "reference/param/generated/param.parameterized.Parameters.inspect_value", "reference/param/generated/param.parameterized.Parameters.log", "reference/param/generated/param.parameterized.Parameters.message", "reference/param/generated/param.parameterized.Parameters.method_dependencies", "reference/param/generated/param.parameterized.Parameters.objects", "reference/param/generated/param.parameterized.Parameters.outputs", "reference/param/generated/param.parameterized.Parameters.params", "reference/param/generated/param.parameterized.Parameters.params_depended_on", "reference/param/generated/param.parameterized.Parameters.pprint", "reference/param/generated/param.parameterized.Parameters.print_param_defaults", "reference/param/generated/param.parameterized.Parameters.print_param_values", "reference/param/generated/param.parameterized.Parameters.schema", "reference/param/generated/param.parameterized.Parameters.serialize_parameters", "reference/param/generated/param.parameterized.Parameters.serialize_value", "reference/param/generated/param.parameterized.Parameters.set_default", "reference/param/generated/param.parameterized.Parameters.set_dynamic_time_fn", "reference/param/generated/param.parameterized.Parameters.set_param", "reference/param/generated/param.parameterized.Parameters.trigger", "reference/param/generated/param.parameterized.Parameters.unwatch", "reference/param/generated/param.parameterized.Parameters.update", "reference/param/generated/param.parameterized.Parameters.values", "reference/param/generated/param.parameterized.Parameters.verbose", "reference/param/generated/param.parameterized.Parameters.warning", "reference/param/generated/param.parameterized.Parameters.watch", "reference/param/generated/param.parameterized.Parameters.watch_values", "reference/param/generated/param.parameterized.Parameters.watchers", "reference/param/generated/param.parameterized.Watcher", "reference/param/generated/param.parameterized.batch_call_watchers", "reference/param/generated/param.parameterized.get_logger", "reference/param/generated/param.parameterized.logging_level", "reference/param/generated/param.script_repr", "reference/param/index", "reference/param/logging", "reference/param/param_namespace", "reference/param/parameter_helpers", "reference/param/parameterized_helpers", "reference/param/parameterized_objects", "reference/param/parameters", "reference/param/serialization", "releases", "roadmap", "user_guide/Dependencies_and_Watchers", "user_guide/Dynamic_Parameters", "user_guide/How_Param_Works", "user_guide/Logging_and_Warnings", "user_guide/Outputs", "user_guide/Parameter_Types", "user_guide/ParameterizedFunctions", "user_guide/Parameters", "user_guide/Reactive_Expressions", "user_guide/Serialization_and_Persistence", "user_guide/Simplifying_Codebases", "user_guide/index"], "filenames": ["about.md", "comparisons.md", "developer_guide.md", "getting_started.md", "index.md", "reference/index.md", "reference/numbergen.md", "reference/param/generated/param.Action.rst", "reference/param/generated/param.Array.rst", "reference/param/generated/param.Boolean.rst", "reference/param/generated/param.Bytes.rst", "reference/param/generated/param.CalendarDateRange.rst", "reference/param/generated/param.Callable.rst", "reference/param/generated/param.ClassSelector.rst", "reference/param/generated/param.Color.rst", "reference/param/generated/param.Composite.rst", "reference/param/generated/param.DataFrame.rst", "reference/param/generated/param.DateRange.rst", "reference/param/generated/param.Dict.rst", "reference/param/generated/param.Dynamic.rst", "reference/param/generated/param.Event.rst", "reference/param/generated/param.FileSelector.rst", "reference/param/generated/param.Filename.rst", "reference/param/generated/param.Foldername.rst", "reference/param/generated/param.HookList.rst", "reference/param/generated/param.Integer.rst", "reference/param/generated/param.List.rst", "reference/param/generated/param.ListSelector.rst", "reference/param/generated/param.Magnitude.rst", "reference/param/generated/param.MultiFileSelector.rst", "reference/param/generated/param.Number.rst", "reference/param/generated/param.NumericTuple.rst", "reference/param/generated/param.ParamOverrides.rst", "reference/param/generated/param.Parameter.rst", "reference/param/generated/param.Parameterized.rst", "reference/param/generated/param.ParameterizedFunction.rst", "reference/param/generated/param.Path.rst", "reference/param/generated/param.Range.rst", "reference/param/generated/param.Selector.rst", "reference/param/generated/param.Series.rst", "reference/param/generated/param.String.rst", "reference/param/generated/param.Tuple.rst", "reference/param/generated/param.XYCoordinates.rst", "reference/param/generated/param.batch_watch.rst", "reference/param/generated/param.concrete_descendents.rst", "reference/param/generated/param.depends.rst", "reference/param/generated/param.discard_events.rst", "reference/param/generated/param.edit_constant.rst", "reference/param/generated/param.get_soft_bounds.rst", "reference/param/generated/param.guess_bounds.rst", "reference/param/generated/param.guess_param_types.rst", "reference/param/generated/param.output.rst", "reference/param/generated/param.param_union.rst", "reference/param/generated/param.parameterized.Event.rst", "reference/param/generated/param.parameterized.Parameters.add_parameter.rst", "reference/param/generated/param.parameterized.Parameters.debug.rst", "reference/param/generated/param.parameterized.Parameters.defaults.rst", "reference/param/generated/param.parameterized.Parameters.deserialize_parameters.rst", "reference/param/generated/param.parameterized.Parameters.deserialize_value.rst", "reference/param/generated/param.parameterized.Parameters.force_new_dynamic_value.rst", "reference/param/generated/param.parameterized.Parameters.get_param_values.rst", "reference/param/generated/param.parameterized.Parameters.get_value_generator.rst", "reference/param/generated/param.parameterized.Parameters.inspect_value.rst", "reference/param/generated/param.parameterized.Parameters.log.rst", "reference/param/generated/param.parameterized.Parameters.message.rst", "reference/param/generated/param.parameterized.Parameters.method_dependencies.rst", "reference/param/generated/param.parameterized.Parameters.objects.rst", "reference/param/generated/param.parameterized.Parameters.outputs.rst", "reference/param/generated/param.parameterized.Parameters.params.rst", "reference/param/generated/param.parameterized.Parameters.params_depended_on.rst", "reference/param/generated/param.parameterized.Parameters.pprint.rst", "reference/param/generated/param.parameterized.Parameters.print_param_defaults.rst", "reference/param/generated/param.parameterized.Parameters.print_param_values.rst", "reference/param/generated/param.parameterized.Parameters.schema.rst", "reference/param/generated/param.parameterized.Parameters.serialize_parameters.rst", "reference/param/generated/param.parameterized.Parameters.serialize_value.rst", "reference/param/generated/param.parameterized.Parameters.set_default.rst", "reference/param/generated/param.parameterized.Parameters.set_dynamic_time_fn.rst", "reference/param/generated/param.parameterized.Parameters.set_param.rst", "reference/param/generated/param.parameterized.Parameters.trigger.rst", "reference/param/generated/param.parameterized.Parameters.unwatch.rst", "reference/param/generated/param.parameterized.Parameters.update.rst", "reference/param/generated/param.parameterized.Parameters.values.rst", "reference/param/generated/param.parameterized.Parameters.verbose.rst", "reference/param/generated/param.parameterized.Parameters.warning.rst", "reference/param/generated/param.parameterized.Parameters.watch.rst", "reference/param/generated/param.parameterized.Parameters.watch_values.rst", "reference/param/generated/param.parameterized.Parameters.watchers.rst", "reference/param/generated/param.parameterized.Watcher.rst", "reference/param/generated/param.parameterized.batch_call_watchers.rst", "reference/param/generated/param.parameterized.get_logger.rst", "reference/param/generated/param.parameterized.logging_level.rst", "reference/param/generated/param.script_repr.rst", "reference/param/index.md", "reference/param/logging.md", "reference/param/param_namespace.md", "reference/param/parameter_helpers.md", "reference/param/parameterized_helpers.md", "reference/param/parameterized_objects.md", "reference/param/parameters.md", "reference/param/serialization.md", "releases.md", "roadmap.md", "user_guide/Dependencies_and_Watchers.ipynb", "user_guide/Dynamic_Parameters.ipynb", "user_guide/How_Param_Works.ipynb", "user_guide/Logging_and_Warnings.ipynb", "user_guide/Outputs.ipynb", "user_guide/Parameter_Types.ipynb", "user_guide/ParameterizedFunctions.ipynb", "user_guide/Parameters.ipynb", "user_guide/Reactive_Expressions.ipynb", "user_guide/Serialization_and_Persistence.ipynb", "user_guide/Simplifying_Codebases.ipynb", "user_guide/index.md"], "titles": ["About", "Comparison to other approaches", "Developer guide", "Getting Started", "Welcome to Param!", "API reference", "Numbergen API reference", "param.Action", "param.Array", "param.Boolean", "param.Bytes", "param.CalendarDateRange", "param.Callable", "param.ClassSelector", "param.Color", "param.Composite", "param.DataFrame", "param.DateRange", "param.Dict", "param.Dynamic", "param.Event", "param.FileSelector", "param.Filename", "param.Foldername", "param.HookList", "param.Integer", "param.List", "param.ListSelector", "param.Magnitude", "param.MultiFileSelector", "param.Number", "param.NumericTuple", "param.ParamOverrides", "param.Parameter", "param.Parameterized", "param.ParameterizedFunction", "param.Path", "param.Range", "param.Selector", "param.Series", "param.String", "param.Tuple", "param.XYCoordinates", "param.batch_watch", "param.concrete_descendents", "param.depends", "param.discard_events", "param.edit_constant", "param.get_soft_bounds", "param.guess_bounds", "param.guess_param_types", "param.output", "param.param_union", "param.parameterized.Event", "param.parameterized.Parameters.add_parameter", "param.parameterized.Parameters.debug", "param.parameterized.Parameters.defaults", "param.parameterized.Parameters.deserialize_parameters", "param.parameterized.Parameters.deserialize_value", "param.parameterized.Parameters.force_new_dynamic_value", "param.parameterized.Parameters.get_param_values", "param.parameterized.Parameters.get_value_generator", "param.parameterized.Parameters.inspect_value", "param.parameterized.Parameters.log", "param.parameterized.Parameters.message", "param.parameterized.Parameters.method_dependencies", "param.parameterized.Parameters.objects", "param.parameterized.Parameters.outputs", "param.parameterized.Parameters.params", "param.parameterized.Parameters.params_depended_on", "param.parameterized.Parameters.pprint", "param.parameterized.Parameters.print_param_defaults", "param.parameterized.Parameters.print_param_values", "param.parameterized.Parameters.schema", "param.parameterized.Parameters.serialize_parameters", "param.parameterized.Parameters.serialize_value", "param.parameterized.Parameters.set_default", "param.parameterized.Parameters.set_dynamic_time_fn", "param.parameterized.Parameters.set_param", "param.parameterized.Parameters.trigger", "param.parameterized.Parameters.unwatch", "param.parameterized.Parameters.update", "param.parameterized.Parameters.values", "param.parameterized.Parameters.verbose", "param.parameterized.Parameters.warning", "param.parameterized.Parameters.watch", "param.parameterized.Parameters.watch_values", "param.parameterized.Parameters.watchers", "param.parameterized.Watcher", "param.parameterized.batch_call_watchers", "param.parameterized.get_logger", "param.parameterized.logging_level", "param.script_repr", "Param API reference", "Logging", ".param namespace", "Parameter helpers", "Parameterized helpers", "Parameterized objects", "Parameters", "Serialization", "Releases", "Roadmap", "Dependencies and Watchers", "Dynamic parameter values", "How Param Works", "Logging and Warnings", "Outputs", "Parameter types", "ParameterizedFunctions", "Parameters and Parameterized objects", "Reactive Functions & Expressions", "Serialization and Persistence", "Simplifying Codebases", "User Guide"], "terms": {"param": [0, 1, 2, 5, 6, 100, 101, 102, 106, 107, 109, 110, 111, 112, 113, 114], "i": [0, 1, 2, 3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 26, 27, 29, 30, 31, 32, 33, 34, 36, 37, 38, 39, 40, 41, 42, 45, 48, 51, 53, 59, 61, 77, 78, 79, 84, 85, 88, 92, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113], "complet": [0, 2, 20, 85, 92, 101, 103, 106, 112, 113], "open": [0, 101, 102, 108, 112], "sourc": [0, 2, 3, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 88, 89, 90, 91, 92, 93, 100, 101, 102, 110, 112, 113], "avail": [0, 1, 3, 6, 32, 93, 95, 101, 103, 106, 108, 110, 112, 113, 114], "under": [0, 5, 93, 95, 101, 105], "bsd": 0, "licens": 0, "freeli": [0, 3, 110], "both": [0, 1, 4, 6, 13, 30, 101, 103, 104, 105, 108, 110, 111, 112, 113], "commerci": 0, "non": [0, 4, 25, 26, 28, 30, 33, 44, 56, 104, 106, 109, 110, 111, 112, 113], "us": [0, 1, 4, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 19, 20, 21, 22, 23, 24, 26, 27, 29, 30, 32, 33, 34, 36, 38, 39, 40, 49, 51, 52, 55, 56, 60, 64, 65, 66, 68, 69, 71, 72, 76, 78, 81, 83, 86, 92, 93, 100, 101, 102, 105, 106, 107, 108, 109, 110, 113, 114], "wa": [0, 1, 19, 34, 53, 101, 103, 104, 105, 106, 108, 110, 111, 112, 113], "origin": [0, 1, 101, 102, 103, 110, 111, 112], "develop": [0, 1, 101, 102, 104, 112, 113, 114], "univers": 0, "texa": 0, "austin": 0, "edinburgh": 0, "fund": [0, 102], "from": [0, 1, 3, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 19, 20, 21, 22, 23, 24, 26, 27, 29, 30, 33, 34, 36, 38, 39, 40, 44, 51, 63, 68, 77, 80, 92, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113], "u": [0, 110], "nation": 0, "institut": 0, "health": 0, "grant": 0, "1r01": 0, "mh66991": 0, "now": [0, 3, 101, 103, 104, 106, 108, 109, 110, 111, 112, 113], "maintain": [0, 1, 3, 4, 101, 102, 113], "anaconda": 0, "inc": 0, "commun": [0, 112], "contributor": [0, 102], "part": [0, 1, 101, 113], "holoviz": [0, 2, 101, 102, 103, 111], "famili": 0, "tool": [0, 1, 102, 103, 104], "The": [0, 1, 2, 3, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 26, 27, 29, 30, 31, 33, 34, 36, 37, 38, 39, 40, 41, 42, 45, 48, 51, 92, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113], "org": [0, 6, 103, 111], "websit": [0, 101, 102, 104], "show": [0, 101, 104, 108, 110, 112], "how": [0, 3, 4, 6, 26, 34, 102, 103, 104, 106, 108, 109, 110, 111, 112, 113, 114], "togeth": [0, 104, 105, 107, 110, 111], "other": [0, 3, 4, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 19, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 45, 85, 92, 101, 102, 103, 104, 106, 107, 108, 109, 111, 112, 113], "librari": [0, 1, 3, 4, 102, 103, 104, 105, 112, 113], "solv": [0, 1, 102], "complex": [0, 33, 102, 103, 104, 105, 110, 111, 112], "problem": [0, 1, 101, 111, 113], "detail": [0, 3, 6, 55, 63, 64, 70, 83, 84, 101, 103, 104, 105, 106, 108, 110, 112, 114], "tutori": 0, "exampl": [0, 2, 6, 30, 33, 34, 40, 101, 102, 103, 104, 105, 107, 108, 109, 110, 111, 112, 113], "each": [0, 1, 3, 4, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 19, 20, 21, 22, 23, 24, 26, 27, 29, 30, 33, 34, 36, 38, 39, 40, 48, 65, 69, 78, 85, 92, 102, 103, 104, 105, 106, 108, 110, 111, 112], "build": [0, 1, 101, 102, 103, 107, 108, 109], "do": [0, 1, 3, 4, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 44, 85, 103, 104, 105, 106, 108, 109, 110, 112, 113], "mani": [0, 1, 6, 20, 101, 102, 103, 104, 105, 106, 108, 110], "project": [0, 2, 4, 101, 102, 104], "If": [0, 3, 4, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 19, 20, 21, 22, 23, 24, 26, 27, 29, 32, 33, 34, 36, 38, 39, 40, 49, 51, 59, 66, 77, 88, 92, 101, 103, 104, 105, 106, 107, 108, 109, 110, 112, 113], "you": [0, 1, 2, 3, 4, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 66, 101, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114], "have": [0, 1, 3, 4, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 30, 33, 36, 38, 39, 40, 44, 52, 61, 62, 79, 85, 92, 101, 102, 103, 104, 105, 108, 109, 110, 111, 112, 113, 114], "ani": [0, 1, 2, 3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 21, 22, 23, 24, 26, 27, 29, 31, 32, 33, 34, 36, 37, 38, 39, 40, 41, 42, 46, 51, 67, 77, 89, 92, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113], "question": [0, 110], "usag": [0, 1, 3, 4, 101, 102, 104, 112, 113], "issu": [0, 1, 2, 3, 101, 102, 110, 112], "visit": 0, "discours": 0, "forum": 0, "want": [0, 3, 4, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 103, 104, 106, 107, 108, 109, 110, 111, 112], "report": [0, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 101, 105, 110, 113], "bug": [0, 101], "request": [0, 19, 30, 66, 103, 105, 108], "new": [0, 3, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 19, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 53, 54, 59, 85, 92, 101, 103, 104, 105, 108, 110, 111, 112], "featur": [0, 1, 3, 101, 102, 104, 105, 108, 109, 112, 113], "first": [0, 1, 3, 6, 38, 44, 85, 101, 102, 103, 104, 106, 108, 109, 110, 111, 113], "see": [0, 1, 3, 4, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 17, 18, 20, 21, 22, 23, 24, 26, 27, 29, 30, 33, 34, 36, 38, 39, 40, 55, 63, 64, 65, 69, 70, 83, 84, 85, 92, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113], "": [0, 1, 3, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 19, 20, 21, 22, 23, 24, 26, 27, 29, 33, 34, 36, 38, 39, 40, 45, 54, 55, 61, 63, 64, 71, 72, 80, 83, 84, 91, 101, 102, 103, 104, 105, 106, 107, 108, 110, 111, 112, 113], "alreadi": [0, 3, 101, 102, 103, 108, 110, 112, 113], "our": [0, 4, 101, 103, 110, 112], "list": [0, 1, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 27, 29, 33, 34, 36, 38, 39, 40, 60, 80, 86, 88, 92, 101, 102, 103, 104, 110, 112, 113], "add": [0, 1, 3, 4, 54, 101, 103, 104, 105, 110, 111, 112, 113], "one": [0, 1, 20, 21, 30, 34, 38, 54, 92, 93, 100, 102, 103, 104, 105, 106, 107, 108, 110, 111, 112, 113], "need": [0, 1, 3, 4, 33, 38, 92, 101, 103, 104, 105, 108, 109, 110, 111, 112, 113], "like": [0, 1, 3, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 35, 36, 38, 39, 40, 63, 101, 102, 103, 104, 105, 106, 108, 109, 110, 111, 112, 113], "built": [0, 2, 103, 104, 112], "someth": [0, 33, 103, 110, 111, 112], "share": [0, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 103, 104, 105, 108, 112], "tweet": 0, "link": [0, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 101, 103], "screenshot": 0, "your": [0, 2, 3, 4, 101, 102, 104, 106, 108, 109, 110, 112, 113, 114], "latest": 0, "creation": [0, 6, 103, 111], "holoviz_org": 0, "thank": [0, 101, 111], "2003": [1, 102], "python": [1, 3, 4, 6, 12, 34, 35, 51, 55, 63, 64, 83, 84, 92, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113], "2": [1, 3, 6, 12, 33, 40, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113], "1": [1, 3, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 28, 29, 30, 33, 34, 36, 38, 39, 40, 55, 56, 60, 64, 68, 71, 72, 76, 78, 83, 103, 104, 105, 106, 107, 108, 110, 111, 112], "long": [1, 19, 38, 101, 103, 110, 111], "run": [1, 2, 3, 43, 44, 92, 101, 103, 104, 106, 111, 112], "brain": 1, "simul": [1, 3, 103, 104, 106, 111], "made": [1, 6, 34, 101, 102, 104, 106, 111, 113], "separ": [1, 3, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 30, 33, 36, 38, 39, 40, 70, 92, 101, 103, 104, 108, 109, 110, 111, 112], "packag": [1, 5, 44, 101, 103], "github": [1, 2, 101, 102], "2012": 1, "In": [1, 7, 85, 103, 105, 108, 110, 111, 112, 113], "interim": 1, "varieti": [1, 104], "some": [1, 3, 6, 19, 20, 24, 50, 101, 102, 103, 104, 106, 107, 108, 110, 111, 112, 113], "same": [1, 3, 5, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 51, 52, 61, 62, 85, 92, 103, 104, 105, 106, 107, 108, 110, 111, 112, 113], "been": [1, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 44, 52, 79, 85, 88, 92, 101, 102, 103, 105, 106, 108, 110, 111, 112, 113], "includ": [1, 3, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 44, 63, 68, 92, 101, 103, 104, 108, 110, 112], "trait": 1, "traitlet": [1, 102], "attr": [1, 102], "option": [1, 3, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 30, 33, 34, 36, 37, 38, 39, 40, 45, 52, 101, 104, 106, 107, 108, 110, 111, 112], "strict": [1, 104], "django": [1, 102], "model": [1, 3, 102, 103, 104, 111], "pydant": [1, 101, 102], "plu": [1, 4, 63, 101, 103, 113], "itself": [1, 19, 20, 32, 92, 101, 102, 103, 105, 106, 107, 108, 110, 111, 112, 113], "ha": [1, 3, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 30, 33, 34, 36, 38, 39, 40, 56, 60, 65, 69, 79, 82, 88, 101, 102, 103, 104, 105, 106, 108, 110, 111, 112, 113], "incorpor": 1, "mechan": [1, 103, 105, 108, 110, 111, 112], "address": [1, 40, 102, 113], "3": [1, 3, 31, 40, 41, 102, 103, 104, 105, 107, 108, 109, 110, 111, 112, 113], "6": [1, 3, 6, 31, 33, 41, 103, 104, 107, 108, 110, 111, 112, 113], "type": [1, 3, 4, 6, 10, 15, 17, 24, 26, 30, 33, 50, 51, 52, 53, 67, 79, 93, 100, 101, 102, 103, 104, 105, 107, 109, 111, 112, 113, 114], "annot": [1, 45, 51, 101, 102, 107], "7": [1, 3, 31, 41, 103, 104, 108, 109, 111], "data": [1, 3, 38, 102, 103, 105, 107, 108, 110, 111, 112, 113], "class": [1, 3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 44, 45, 51, 53, 54, 60, 66, 68, 76, 77, 78, 81, 82, 88, 93, 95, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114], "namedtupl": 1, "properti": [1, 3, 33, 87, 93, 95, 103, 110, 112, 113], "overlap": 1, "mean": [1, 6, 30, 103, 104, 108], "all": [1, 3, 4, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 32, 33, 36, 38, 39, 40, 44, 52, 56, 60, 66, 71, 72, 77, 85, 89, 101, 103, 104, 105, 107, 108, 109, 110, 111, 112, 113], "function": [1, 3, 4, 6, 7, 12, 19, 30, 34, 35, 45, 70, 85, 88, 101, 104, 107, 108, 109, 112, 113, 114], "provid": [1, 3, 4, 6, 7, 12, 24, 30, 33, 34, 38, 63, 85, 89, 92, 101, 103, 104, 105, 106, 108, 109, 110, 111, 112, 113, 114], "describ": [1, 3, 33, 101, 103, 104, 105, 106, 110], "below": [1, 101, 103, 104, 110], "also": [1, 2, 3, 4, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 30, 32, 33, 36, 38, 39, 40, 51, 66, 78, 81, 85, 101, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113], "an": [1, 3, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 25, 26, 27, 29, 30, 32, 33, 35, 36, 38, 39, 40, 42, 51, 53, 60, 77, 82, 84, 88, 93, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113], "user": [1, 3, 4, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 34, 36, 38, 39, 40, 101, 102, 103, 104, 105, 106, 108, 109, 110, 111, 112, 113], "which": [1, 3, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 30, 33, 34, 36, 38, 39, 40, 51, 56, 62, 77, 79, 85, 88, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113], "were": [1, 101, 103, 106, 110], "written": [1, 102, 104, 106, 111, 113], "about": [1, 3, 4, 34, 45, 102, 103, 104, 105, 106, 108, 110, 111, 112, 113, 114], "appli": [1, 3, 6, 102, 108, 110, 111, 112, 113], "just": [1, 3, 4, 101, 103, 104, 105, 106, 108, 110, 111, 112, 113], "well": [1, 3, 7, 103, 104, 110, 111, 112, 113], "differ": [1, 3, 6, 19, 33, 92, 93, 100, 101, 103, 104, 105, 110, 111, 112, 113], "e": [1, 2, 3, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 30, 31, 33, 36, 38, 39, 40, 41, 51, 59, 61, 77, 85, 92, 93, 100, 101, 102, 103, 104, 105, 106, 107, 108, 110, 111, 112], "g": [1, 3, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 30, 31, 33, 36, 38, 39, 40, 41, 51, 77, 85, 92, 93, 100, 101, 102, 103, 104, 105, 106, 107, 108, 110, 111, 112], "support": [1, 3, 4, 6, 15, 34, 63, 93, 100, 101, 102, 103, 104, 105, 106, 108, 109, 110, 111, 112], "info": [1, 63, 106], "compar": [1, 101, 103, 106, 112], "here": [1, 3, 33, 34, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113], "we": [1, 3, 101, 103, 104, 105, 106, 107, 108, 110, 111, 112, 113], "word": [1, 104, 111], "paramet": [1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 34, 35, 36, 37, 38, 39, 40, 41, 42, 45, 47, 49, 50, 51, 52, 53, 88, 89, 92, 100, 101, 102, 105, 107, 109, 112, 113, 114], "term": [1, 101], "attribut": [1, 3, 4, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 53, 59, 61, 62, 77, 88, 92, 101, 103, 104, 108, 109, 110, 112, 113], "hastrait": 1, "ib": 1, "can": [1, 2, 3, 4, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 19, 20, 21, 22, 23, 24, 26, 27, 29, 30, 33, 34, 36, 38, 39, 40, 45, 51, 77, 78, 92, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113], "express": [1, 3, 6, 10, 40, 45, 51, 93, 100, 101, 103, 108, 110, 113, 114], "nearli": [1, 3, 92, 101, 113], "anyth": [1, 110, 111, 112, 113], "thei": [1, 3, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 45, 101, 102, 103, 104, 105, 107, 108, 110, 111, 112, 113], "requir": [1, 2, 3, 4, 13, 19, 25, 28, 33, 36, 92, 102, 103, 104, 105, 108, 110, 111, 112, 113], "least": [1, 3, 105, 108, 112, 113], "order": [1, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 63, 101, 103, 104, 107, 108, 110, 111], "magnitud": [1, 108], "more": [1, 4, 33, 34, 70, 78, 92, 93, 100, 101, 102, 103, 104, 105, 106, 107, 108, 110, 111, 112, 113], "think": [1, 105, 113], "pre": [1, 105, 108], "implement": [1, 33, 35, 40, 93, 100, 101, 102, 105, 108, 109, 110, 111, 112, 113], "configur": [1, 104, 106, 108, 110, 112, 113, 114], "avoid": [1, 3, 66, 101, 103, 106, 110, 111], "write": [1, 3, 104, 108, 109, 110, 111, 113, 114], "time": [1, 3, 6, 19, 33, 101, 102, 103, 105, 106, 110, 111, 112, 113], "big": 1, "win": 1, "becaus": [1, 3, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 78, 103, 104, 105, 108, 109, 110, 111, 112, 113], "ar": [1, 3, 4, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 32, 33, 35, 36, 38, 39, 40, 44, 45, 51, 60, 65, 67, 69, 77, 82, 85, 88, 92, 93, 95, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113], "over": [1, 3, 6, 33, 104, 105, 106, 110, 112, 113], "codebas": [1, 3, 4, 110, 114], "base": [1, 4, 6, 34, 50, 93, 100, 101, 102, 103, 104, 107, 108, 110, 113], "lead": 1, "much": [1, 4, 101, 105, 110, 111, 112, 113], "simpler": [1, 4, 101, 102], "specif": [1, 3, 4, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 51, 86, 101, 102, 103, 104, 105, 106, 108, 110, 111, 112, 113], "where": [1, 3, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 101, 103, 104, 106, 108, 109, 110, 112, 113], "automat": [1, 3, 4, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 34, 35, 36, 38, 39, 40, 101, 102, 103, 105, 108, 109, 110, 111, 113, 114], "valid": [1, 3, 4, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 101, 102, 103, 108, 110, 112, 113], "bound": [1, 3, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 33, 36, 37, 38, 39, 40, 48, 49, 93, 100, 101, 103, 104, 105, 107, 108, 110, 111, 112, 113], "simpl": [1, 4, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 50, 103, 104, 105, 107, 110, 111, 112, 113], "local": [1, 103, 105, 106, 108, 111], "line": [1, 3, 112, 113], "declar": [1, 3, 4, 19, 30, 33, 51, 54, 67, 85, 88, 101, 102, 103, 104, 105, 107, 108, 110, 111, 112, 113], "integ": [1, 3, 6, 16, 39, 93, 100, 101, 103, 104, 108, 110, 111, 112, 113], "5": [1, 3, 4, 6, 30, 31, 33, 34, 40, 41, 103, 104, 105, 106, 107, 108, 110, 111, 112, 113], "10": [1, 3, 6, 30, 103, 104, 107, 108, 109, 110, 111, 112], "chang": [1, 3, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 21, 22, 23, 24, 26, 27, 29, 31, 33, 34, 36, 37, 38, 39, 40, 41, 42, 53, 77, 79, 85, 86, 88, 101, 102, 103, 104, 105, 108, 110, 111, 112, 114], "constructor": [1, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 34, 36, 38, 39, 40, 101, 105, 110, 112, 113], "explicit": [1, 101, 102, 103, 104, 111, 113], "get": [1, 4, 15, 19, 30, 34, 92, 101, 103, 104, 105, 108, 110, 112, 113, 114], "set": [1, 3, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 19, 20, 21, 22, 23, 24, 26, 27, 29, 30, 33, 34, 36, 38, 39, 40, 47, 49, 50, 52, 53, 60, 66, 76, 77, 78, 79, 81, 82, 85, 88, 89, 92, 101, 103, 104, 105, 106, 108, 109, 110, 112, 113, 114], "method": [1, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 45, 51, 53, 65, 67, 69, 88, 93, 95, 101, 102, 103, 104, 105, 106, 107, 108, 109, 112, 113], "half": [1, 6], "dozen": [1, 3, 113], "though": [1, 6, 13, 102, 103, 104, 106, 110, 112], "thi": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 33, 34, 35, 36, 38, 39, 40, 45, 51, 53, 54, 60, 61, 65, 66, 68, 69, 72, 73, 77, 78, 80, 81, 82, 85, 88, 89, 92, 101, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114], "mai": [1, 3, 15, 16, 19, 20, 39, 51, 66, 70, 81, 92, 103, 106, 107, 108, 112, 113], "seem": 1, "easi": [1, 3, 103, 104, 108, 110, 111, 113], "difficult": [1, 103, 111, 113], "read": [1, 33, 34, 101, 103, 104, 105, 108, 110, 111, 112, 113], "make": [1, 3, 4, 6, 101, 102, 103, 104, 105, 106, 108, 109, 110, 111, 112, 113, 114], "comprehens": [1, 101], "exhaust": [1, 108], "practic": [1, 104, 110, 112], "most": [1, 61, 101, 103, 105, 108, 110, 111, 112, 113], "programm": [1, 4, 103, 110, 113], "simpli": [1, 3, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 51, 61, 103, 105, 111, 112], "skip": [1, 104, 108, 112], "onli": [1, 3, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 19, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 44, 60, 66, 82, 85, 86, 88, 92, 101, 102, 103, 104, 106, 108, 110, 111, 112, 113], "partial": [1, 111], "leav": [1, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 110], "behav": [1, 3, 104, 105, 108, 109, 110, 111], "undefin": [1, 7, 11, 15, 17, 22, 23, 24, 25, 31, 36], "wai": [1, 2, 3, 4, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 92, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112], "unexpect": [1, 106], "input": [1, 3, 107, 108, 110, 113, 114], "With": [1, 3, 103, 105, 111, 113], "don": [1, 101, 103, 104, 105, 109, 110], "t": [1, 3, 4, 6, 34, 101, 102, 103, 104, 105, 106, 108, 109, 110, 111, 112, 113], "choos": [1, 3, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 103, 104, 108, 109], "between": [1, 33, 36, 67, 103, 104, 106, 108, 110, 111, 112, 113, 114], "short": [1, 103], "readabl": [1, 4, 108, 112, 113], "heavili": 1, "far": [1, 103, 111, 113], "less": [1, 4, 6, 105], "work": [1, 3, 4, 6, 101, 102, 103, 104, 108, 110, 111, 112, 113, 114], "benefit": [1, 108, 113], "treat": [1, 6, 33, 105, 108, 110, 112], "extra": [1, 3, 104, 109, 111], "step": [1, 6, 11, 17, 24, 25, 28, 30, 33, 37, 101, 104, 108], "typic": [1, 6, 24, 30, 92, 102, 103, 104, 105, 106, 107, 108, 110, 113], "verbos": [1, 63, 101, 104, 106, 110, 111], "allow": [1, 3, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 26, 27, 29, 30, 31, 33, 36, 37, 38, 39, 40, 41, 42, 47, 51, 85, 86, 101, 103, 104, 105, 106, 107, 108, 110, 111, 112, 113, 114], "specifi": [1, 3, 6, 11, 15, 16, 17, 22, 23, 24, 26, 30, 32, 33, 36, 38, 44, 45, 51, 77, 93, 100, 103, 104, 105, 107, 108, 110, 112], "return": [1, 3, 6, 15, 19, 22, 23, 32, 33, 35, 36, 44, 48, 49, 51, 52, 56, 59, 60, 61, 62, 65, 66, 67, 68, 69, 73, 82, 85, 101, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113], "normal": [1, 6, 103, 104, 105, 110, 111, 112, 113], "so": [1, 3, 4, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 19, 20, 21, 22, 23, 24, 26, 27, 29, 30, 33, 36, 38, 39, 40, 44, 77, 79, 92, 101, 102, 103, 104, 105, 106, 108, 109, 110, 111, 112, 113], "role": [1, 105], "error": [1, 2, 3, 4, 63, 101, 104, 105, 106, 112, 113, 114], "limit": [1, 104, 108], "cannot": [1, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 104, 108, 110, 111, 112], "enforc": [1, 6, 26, 30, 108, 110, 113], "constraint": [1, 102, 108, 110, 112], "rang": [1, 3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 21, 22, 23, 24, 26, 27, 28, 29, 30, 33, 36, 38, 39, 40, 101, 103, 104, 108, 110, 111, 112, 113], "state": [1, 4, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 92, 101, 102, 103, 104, 105, 106, 110, 111, 112, 114], "must": [1, 3, 6, 11, 12, 16, 17, 19, 30, 31, 32, 36, 37, 38, 41, 42, 108, 110, 113], "alabama": 1, "alaska": 1, "thu": [1, 3, 6, 20, 102, 103, 104, 105, 108, 111, 112, 113], "even": [1, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 101, 103, 104, 106, 110, 111, 112, 113], "hint": [1, 108], "still": [1, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 48, 101, 102, 103, 108, 109, 110, 111, 112, 113], "actual": [1, 3, 6, 30, 79, 88, 103, 104, 105, 106, 108, 110, 111, 112, 113], "note": [1, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 19, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 56, 101, 102, 103, 108, 110, 111, 112, 113], "focus": 1, "output": [1, 3, 34, 92, 101, 103, 104, 106, 108, 111, 112, 114], "rather": [1, 4, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 86, 101, 103, 105, 108, 109, 110, 112, 113], "than": [1, 4, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 86, 92, 101, 103, 104, 105, 108, 109, 110, 112, 113], "detect": [1, 104, 112, 113], "invalid": [1, 110, 112], "suitabl": [1, 92, 101, 107, 108, 112, 113], "applic": [1, 93, 100, 102, 103, 104, 106, 110, 111], "discuss": [1, 102, 104, 108, 110], "variou": [1, 3, 101, 102, 103, 104, 105, 107, 108, 109, 110, 112], "abov": [1, 3, 34, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113], "standard": [1, 3, 4, 6, 33, 34, 104, 106, 108, 112, 113], "version": [1, 55, 56, 60, 64, 68, 71, 72, 76, 78, 83, 86, 103, 111, 112, 113], "indic": [1, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 30, 33, 36, 38, 39, 40, 63, 85, 101, 102, 103, 104, 106, 107, 108], "depend": [1, 2, 3, 6, 15, 20, 65, 69, 85, 101, 104, 105, 108, 109, 110, 111, 112, 114], "process": [1, 3, 24, 33, 85, 88, 102, 103, 104, 105, 108, 109, 111, 112, 113], "restrict": [1, 38, 101, 108, 110, 112], "yourself": [1, 112], "ad": [1, 101, 103, 105, 108, 110, 111, 112], "pure": [1, 105], "minim": 1, "them": [1, 3, 6, 15, 47, 52, 88, 89, 101, 103, 104, 108, 110, 111, 112, 113], "straightforward": [1, 3, 113], "wide": [1, 103, 112], "usabl": [1, 101, 110, 112], "case": [1, 3, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 30, 33, 34, 36, 38, 39, 40, 60, 79, 85, 101, 102, 103, 105, 106, 108, 109, 110, 111, 112, 113], "recent": 1, "languag": [1, 3, 102, 105, 109, 112], "offer": [1, 3, 110, 112], "web": [1, 3, 108], "extens": [1, 101, 103, 104, 105, 111, 112], "framework": [1, 102], "reli": [1, 2, 101, 103, 104], "databas": [1, 112], "server": [1, 103], "dedic": 1, "site": [1, 2, 103, 114], "unlik": [1, 3, 103, 110, 112], "veri": [1, 3, 102, 103, 104, 110, 111, 112, 113], "heavyweight": 1, "solut": 1, "instal": [1, 2, 5, 101, 111, 112], "c": [1, 103, 104, 105, 108, 110, 112], "compil": 1, "larg": [1, 3, 6, 104, 107, 108, 110], "suit": [1, 3, 103], "sever": [1, 33, 34, 63, 106, 108, 112], "map": [1, 7, 51, 67, 107, 108, 109, 112], "widget": [1, 3, 101, 103, 104, 111], "although": [1, 101, 111], "could": [1, 3, 4, 48, 102, 103, 104, 105, 106, 107, 110, 111, 112, 113], "principl": 1, "certain": [1, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 85, 101, 103, 104, 110, 111, 112], "interfac": [1, 3, 4, 33, 78, 101, 103, 104, 108, 111, 112], "current": [1, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 19, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 59, 62, 77, 85, 88, 102, 103, 104, 108, 110, 111, 112], "panel": [1, 3, 101, 103, 107, 111, 114], "jupyt": [1, 103, 111], "bokeh": 1, "parameterizedobject": 1, "paramtk": 1, "unsupport": [1, 101], "tkinter": 1, "ipywidget": [1, 111], "without": [1, 2, 3, 33, 51, 62, 101, 102, 103, 104, 105, 106, 107, 108, 110, 111, 112, 113, 114], "traitsui": 1, "wxwidget": 1, "qt": 1, "suppli": [1, 3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 21, 22, 23, 24, 26, 27, 29, 31, 32, 33, 34, 36, 37, 38, 39, 40, 41, 42, 45, 46, 89, 92, 101, 103, 104, 106, 108, 112, 113], "initi": [1, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 33, 34, 36, 37, 38, 39, 40, 41, 42, 92, 101, 104, 108, 111, 112], "default": [1, 2, 3, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 33, 34, 36, 37, 38, 39, 40, 41, 42, 45, 48, 51, 52, 60, 65, 69, 71, 72, 76, 82, 85, 92, 101, 103, 104, 105, 106, 107, 108, 109, 110, 112, 113, 114], "comput": [1, 103, 104, 105, 107, 108, 111, 112, 113], "modul": [1, 3, 6, 34, 44, 55, 63, 64, 83, 84, 92, 101, 104, 106, 112], "load": [1, 93, 100, 108, 111, 112], "author": [1, 3, 104, 105, 109, 110, 113], "given": [1, 6, 13, 16, 21, 29, 30, 34, 49, 50, 52, 65, 69, 78, 79, 80, 81, 85, 93, 100, 103, 104, 105, 107, 108, 110, 111, 112, 113], "access": [1, 3, 101, 103, 104, 108, 109, 110], "import": [1, 3, 5, 44, 70, 92, 101, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113], "sleep": [1, 103, 111], "tr": 1, "A": [1, 3, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 21, 22, 23, 24, 26, 27, 29, 30, 31, 32, 33, 36, 37, 38, 39, 40, 41, 42, 88, 101, 103, 104, 105, 106, 108, 109, 110, 111, 112], "instantiation_tim": 1, "float": [1, 77, 93, 100, 104, 108], "def": [1, 3, 33, 40, 103, 104, 105, 107, 108, 109, 110, 111, 112, 113], "_look_up_tim": 1, "self": [1, 3, 15, 22, 23, 33, 34, 36, 40, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113], "1634594159": 1, "2040331": 1, "1634594165": 1, "3485172": 1, "1634594167": 1, "812151": 1, "b": [1, 3, 10, 30, 101, 103, 106, 107, 108, 110, 111, 112, 113], "1634594178": 1, "427819": 1, "equival": [1, 51, 54, 59, 76, 112], "decor": [1, 3, 20, 101, 103, 113], "on_init": [1, 45, 101, 103], "true": [1, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 36, 37, 38, 39, 40, 41, 42, 43, 52, 56, 60, 66, 79, 82, 84, 85, 86, 88, 92, 101, 103, 104, 105, 106, 108, 109, 110, 111, 112], "when": [1, 3, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 19, 20, 21, 22, 23, 24, 26, 27, 29, 30, 33, 34, 35, 36, 38, 39, 40, 45, 60, 65, 69, 82, 85, 88, 89, 101, 102, 103, 104, 105, 106, 108, 109, 110, 112, 113, 114], "parameter": [1, 3, 5, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 35, 36, 38, 39, 40, 43, 45, 46, 47, 51, 52, 92, 95, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 111, 113, 114], "instanti": [1, 3, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 33, 35, 36, 37, 38, 39, 40, 41, 42, 56, 92, 101, 103, 105, 106, 108, 109, 112, 113], "On": [1, 12, 112], "hand": [1, 12, 105, 109, 110, 112, 113], "doe": [1, 3, 20, 33, 38, 48, 101, 103, 104, 107, 108, 110, 111, 112, 113], "fulli": [1, 3, 6, 102, 110, 111, 112, 113], "numer": [1, 3, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 33, 36, 37, 38, 39, 40, 49, 88, 93, 100, 104, 108, 110], "instanc": [1, 3, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 19, 20, 21, 22, 23, 24, 26, 27, 29, 30, 33, 34, 35, 36, 38, 39, 40, 45, 49, 53, 60, 66, 77, 82, 87, 88, 93, 95, 101, 103, 104, 105, 106, 108, 111, 112, 113, 114], "val": [1, 92, 108, 110], "number": [1, 6, 11, 16, 17, 19, 31, 33, 34, 37, 39, 41, 42, 51, 77, 93, 100, 101, 103, 107, 110, 111, 112], "0": [1, 3, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 33, 36, 38, 39, 40, 41, 42, 55, 56, 60, 64, 68, 71, 72, 76, 78, 83, 85, 86, 102, 103, 104, 105, 107, 108, 110, 111, 112, 113], "lambda": [1, 3, 104, 106, 108, 112], "1475587455": 1, "437027": 1, "1475587456": 1, "501314": 1, "code": [2, 4, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 54, 101, 102, 104, 105, 106, 108, 110, 111, 112, 113, 114], "host": 2, "To": [2, 3, 4, 35, 51, 66, 101, 103, 104, 106, 108, 109, 110, 111, 112, 113], "clone": 2, "repositori": [2, 101], "follow": [2, 34, 102, 103, 104, 105, 106, 108, 111, 112], "command": [2, 24, 101, 111, 112], "git": [2, 101], "http": [2, 6, 101, 102, 103, 111], "com": [2, 101, 102, 108], "creat": [2, 3, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 30, 33, 36, 38, 39, 40, 45, 66, 101, 103, 104, 108, 110, 111, 112, 113], "directori": [2, 108], "file": [2, 3, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 92, 101, 102, 108, 112, 113, 114], "system": [2, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 101, 103, 104, 107, 108, 110, 112, 113], "locat": [2, 108], "hatch": [2, 103], "manag": [2, 46, 81, 89, 101, 103, 104, 106, 110], "instruct": [2, 110], "onc": [2, 3, 4, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 89, 101, 103, 105, 110, 112, 113], "environ": [2, 101], "activ": 2, "contain": [2, 4, 16, 44, 77, 84, 101, 103, 108, 110, 111, 112], "shell": 2, "simplest": [2, 51, 107], "unit": [2, 101, 104], "check": [2, 3, 4, 25, 26, 28, 30, 33, 101, 102, 103, 104, 105, 108, 109, 110, 111, 112, 113], "notebook": [2, 4, 101, 103, 104, 110, 111, 112], "doc": [2, 3, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 33, 36, 37, 38, 39, 40, 41, 42, 101, 103, 105, 108, 109, 110, 112, 113], "found": [2, 3, 105, 108], "builtdoc": 2, "folder": [2, 23, 36, 101, 108], "outsid": [3, 4, 30, 101, 104, 108, 112], "offici": 3, "releas": [3, 102], "conda": 3, "pypi": [3, 101], "via": [3, 20, 32, 101, 103, 110, 112], "pip": [3, 101], "give": [3, 6, 104, 105, 110], "special": [3, 30, 33, 79, 102, 103, 104, 105, 108, 112], "extend": [3, 105, 112], "dynam": [3, 25, 28, 30, 33, 59, 61, 62, 77, 101, 103, 105, 108, 110, 111, 113, 114], "gener": [3, 6, 19, 30, 33, 59, 61, 62, 77, 85, 92, 101, 102, 103, 105, 106, 107, 108, 110, 111, 112, 113], "valu": [3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 33, 34, 36, 37, 38, 39, 40, 41, 42, 45, 51, 52, 53, 58, 59, 60, 61, 62, 68, 71, 72, 76, 78, 79, 81, 85, 86, 88, 92, 93, 100, 101, 102, 103, 105, 106, 107, 108, 109, 112, 113, 114], "document": [3, 4, 5, 33, 34, 101, 102, 105, 109, 110, 113], "string": [3, 10, 14, 16, 22, 23, 33, 36, 38, 45, 51, 92, 93, 100, 101, 103, 104, 106, 107, 110, 111, 112, 113], "etc": [3, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 104, 106, 108, 112, 114], "inherit": [3, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 51, 77, 101, 102, 103, 104, 105, 108, 112, 113], "parent": 3, "subclass": [3, 13, 33, 35, 44, 101, 105, 108, 110, 112], "titl": [3, 112, 113], "sum": [3, 113], "result": [3, 30, 35, 54, 102, 103, 104, 107, 108, 111, 112, 113], "addend": [3, 113], "second": [3, 111, 113], "__call__": [3, 35, 104, 107, 108, 109, 113], "str": [3, 34, 93, 100, 103, 106, 107, 108, 110, 111, 112, 113], "o1": [3, 113], "4": [3, 12, 31, 40, 103, 104, 106, 108, 109, 110, 111, 112, 113], "9": [3, 40, 103, 104, 108, 111, 112], "As": [3, 30, 79, 103, 104, 105, 107, 108, 110, 111, 112, 113], "defin": [3, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 34, 36, 38, 39, 40, 44, 45, 48, 66, 101, 103, 104, 105, 106, 108, 110, 111, 112, 113], "precis": [3, 103, 104, 107, 110, 111, 113], "quit": [3, 113], "migrat": [3, 113], "exist": [3, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 66, 101, 102, 103, 105, 108, 110, 111, 112, 113], "object": [3, 4, 5, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 32, 33, 34, 36, 38, 39, 40, 45, 46, 47, 51, 52, 53, 54, 56, 60, 61, 65, 69, 71, 72, 73, 77, 78, 80, 81, 82, 85, 86, 88, 89, 92, 100, 101, 102, 105, 106, 107, 108, 109, 113, 114], "accept": [3, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 51, 78, 92, 101, 103, 104, 106, 107, 108, 110, 111, 112, 113], "appropri": [3, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 49, 50, 101, 103, 104, 108, 110, 112], "highest": 3, "superclass": [3, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 19, 20, 21, 22, 23, 24, 26, 27, 29, 33, 34, 36, 38, 39, 40, 68, 105, 108, 109, 110], "its": [3, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 30, 33, 34, 36, 38, 39, 40, 45, 46, 56, 59, 68, 85, 101, 103, 105, 106, 108, 109, 110, 111, 112, 113], "metadata": [3, 45, 101, 103, 105], "ve": [3, 106, 110, 111, 113], "whole": [3, 113], "wealth": [3, 113], "better": [3, 102, 113], "behavior": [3, 33, 101, 105, 108, 110, 111, 112, 113], "unlock": [3, 113], "For": [3, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 34, 36, 38, 39, 40, 48, 61, 78, 81, 101, 103, 104, 106, 109, 110, 111, 112, 113], "what": [3, 4, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 19, 20, 21, 22, 23, 24, 26, 27, 29, 30, 33, 36, 38, 39, 40, 53, 85, 86, 88, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113], "happen": [3, 103, 104, 110, 111, 113], "tri": [3, 113], "inappropri": [3, 4, 106, 113], "caught": [3, 113], "immedi": [3, 85, 88, 103, 111, 113], "four": [3, 33, 103, 108, 110, 113], "valueerror": [3, 108, 110, 112, 113], "o2": [3, 113], "Of": [3, 103, 104, 106, 110, 112, 113], "cours": [3, 103, 104, 106, 110, 112, 113], "alwai": [3, 104, 108, 110, 111, 112, 113], "ordinari": [3, 105, 110, 111, 113], "guid": [3, 4, 101, 103, 104, 111], "quickli": [3, 4, 113], "unwieldi": [3, 113], "except": [3, 30, 62, 84, 93, 100, 101, 102, 105, 106, 108, 110, 112], "assert": [3, 113], "definit": [3, 33, 101, 102, 103, 111, 112], "obscur": [3, 113], "wrote": 3, "let": [3, 4, 103, 104, 105, 107, 108, 110, 111, 112, 113], "focu": [3, 4, 113], "re": [3, 101, 103, 105, 111, 114], "while": [3, 4, 103, 104, 105, 106, 108, 109, 110, 111, 112, 113], "know": [3, 30, 103, 104, 107, 108, 112, 113], "exactli": [3, 16], "remind": 3, "static": [3, 103, 104, 110, 111], "done": [3, 4, 103, 106, 111, 112, 113], "runtim": [3, 108], "help": [3, 6, 65, 69, 85, 102, 103, 104, 105, 106, 107, 110, 112, 113], "program": [3, 4, 103, 104, 106, 107, 108, 110, 111, 112], "correct": [3, 101, 108, 113], "fraction": [3, 113], "huge": [3, 104], "vulner": 3, "potenti": [3, 102, 103, 104, 106, 108, 109, 112, 113], "condit": [3, 106, 113], "ever": [3, 103, 113], "explain": [3, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 105], "simplifi": [3, 101, 114], "improv": [3, 101, 102], "flexibl": [3, 104, 105, 107], "serial": [3, 4, 5, 57, 101, 102, 103, 110, 114], "control": [3, 4, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 19, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 101, 103, 104, 105, 109, 110, 111, 112], "wish": [3, 112], "reconfigur": 3, "o3": [3, 113], "underli": [3, 6, 101, 103, 104, 105, 108, 110, 111, 113], "come": [3, 101, 110], "yaml": [3, 102], "json": [3, 57, 58, 73, 74, 75, 93, 100, 101, 102], "blob": 3, "url": [3, 102, 103, 111], "cli": 3, "argument": [3, 4, 12, 15, 16, 33, 34, 35, 38, 39, 51, 78, 81, 84, 85, 86, 92, 101, 103, 106, 107, 108, 109, 110, 111, 112], "full": [3, 4, 101, 105, 108, 109, 111, 112, 113], "littl": [3, 105, 110], "effort": [3, 110], "up": [3, 4, 38, 85, 88, 89, 101, 103, 104, 108, 110, 111, 112], "job": 3, "valuabl": 3, "particularli": [3, 102, 106], "machin": [3, 103, 104, 112], "pipelin": [3, 107, 108, 111], "evalu": [3, 70, 92, 109, 111, 114], "multipl": [3, 27, 29, 51, 52, 67, 78, 101, 103, 104, 107, 108, 112], "facilit": 3, "callabl": [3, 6, 19, 24, 30, 93, 100, 104, 106, 108, 110, 112, 114], "everi": [3, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 19, 20, 21, 22, 23, 24, 26, 27, 29, 33, 34, 36, 38, 39, 40, 92, 104, 105, 110, 113], "random": [3, 6, 33, 101, 112], "randint": [3, 6, 104], "doesn": [3, 4, 34, 108, 110, 111, 112, 113], "knowledg": [3, 112], "take": [3, 15, 104, 108, 109, 110, 111, 112], "account": 3, "whatev": [3, 108, 110, 111], "lookup": [3, 101, 105, 109], "whether": [3, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 45, 79, 103, 104, 105, 106, 107, 110, 111, 112, 113], "approach": [3, 6, 103, 104, 108, 110, 112], "readi": [3, 101, 102, 104, 108, 112], "across": [3, 52, 104, 110, 112], "numbergen": [3, 5, 101, 112, 114], "stream": [3, 6, 101, 104, 112], "picklabl": [3, 104, 108, 112], "combin": [3, 101, 104, 106], "sweep": [3, 108], "mont": 3, "carlo": 3, "ng": [3, 104], "choic": [3, 5, 6, 104, 108], "uniformrandomint": [3, 5, 6, 104], "ubound": [3, 6, 104], "11": 3, "13": [3, 104], "usual": [3, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 44, 103, 108, 109, 111, 112], "arithmet": [3, 6], "oper": [3, 6, 22, 23, 36, 101, 103, 105, 108, 111], "ab": [3, 6, 30, 104, 108], "mathemat": [3, 104], "constant": [3, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 33, 36, 37, 38, 39, 40, 41, 42, 47, 56, 85, 101, 103, 104, 105, 108, 110], "respect": [3, 13, 101, 102, 104], "global": [3, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 34, 36, 38, 39, 40, 103, 106, 110], "logic": [3, 110, 111], "counter": [3, 103, 104], "synchron": [3, 103, 112], "coordin": [3, 42, 101, 103, 108], "sort": [3, 101, 113], "turn": [3, 103], "out": [3, 4, 101, 103, 104, 105, 106, 108, 113], "inform": [3, 33, 34, 93, 100, 102, 104, 105, 106, 107, 108, 112, 113, 114], "captur": [3, 92, 102, 111, 112], "often": [3, 103, 106, 110], "browser": 3, "displai": [3, 30, 101, 103, 104, 105, 106, 108, 111], "explicitli": [3, 11, 17, 31, 37, 38, 41, 42, 53, 103, 104, 107, 109, 110, 111, 112, 113], "why": [3, 4, 104, 106, 110, 112, 113], "put": [3, 103, 110, 112], "cleanli": 3, "domain": [3, 4, 108], "clearli": [3, 103, 113], "layout": 3, "font": 3, "size": [3, 101, 104, 105], "fundament": [3, 105, 110], "level": [3, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 34, 36, 38, 39, 40, 63, 85, 91, 103, 105, 109, 110, 111, 112, 113], "right": [3, 104, 109, 113], "achiev": [3, 105, 110], "clear": [3, 20, 79, 103, 110, 113], "tightli": [3, 104, 105], "purpos": [3, 101, 102, 103, 104, 108, 112], "easili": [3, 4, 93, 100, 101, 102, 104, 110, 112, 113], "unattend": 3, "batch": [3, 89, 101, 103], "updat": [3, 45, 65, 69, 78, 101, 103, 104, 105, 108, 110, 111], "someon": [3, 33, 103, 113], "goe": 3, "through": [3, 103, 111, 112, 113, 114], "major": [3, 101, 102, 108, 113], "interest": [3, 108, 113], "rest": [3, 4, 102, 105, 108, 113], "fun": 3, "life": [3, 6], "minut": 4, "intro": [4, 101], "video": [4, 101], "download": [4, 103], "handl": [4, 88, 101, 103, 104, 105, 106, 109, 110, 112, 113], "modifi": [4, 62, 91, 101, 103, 104, 108, 109, 110, 112, 113], "It": [4, 19, 102, 104, 105, 112, 113], "robust": [4, 101, 113], "dramat": [4, 113], "reduc": [4, 6, 106, 110], "boilerpl": [4, 114], "possibl": [4, 27, 36, 38, 85, 104, 107, 110, 112, 113], "fact": [4, 112], "front": 4, "tend": 4, "instead": [4, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 35, 36, 38, 39, 40, 55, 56, 60, 64, 68, 71, 72, 76, 78, 83, 101, 103, 104, 105, 106, 108, 109, 111, 112], "manifest": 4, "remain": [4, 110, 111], "clearer": 4, "properli": [4, 6, 15], "keep": [4, 101, 104, 106, 110, 112], "independ": [4, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 105, 108, 110, 112], "gui": [4, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 30, 33, 36, 38, 39, 40, 103, 104, 108, 112, 114], "singl": [4, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 19, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 78, 93, 100, 103, 104, 107, 108, 110, 111, 113], "ui": [4, 108, 111], "expert": 4, "jump": 4, "straight": 4, "start": [4, 6, 17, 33, 92, 101, 103, 104, 105, 108, 110, 112, 113, 114], "effect": [5, 60, 82, 85, 103, 104, 110], "two": [5, 30, 33, 36, 51, 107, 108, 109, 110, 111], "name": [5, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 32, 33, 34, 35, 36, 38, 39, 40, 51, 52, 53, 59, 60, 61, 62, 65, 68, 69, 71, 72, 77, 79, 82, 88, 90, 101, 102, 103, 104, 105, 106, 107, 108, 110, 111, 112], "section": [5, 101, 103, 110, 111], "public": [5, 101, 110], "helper": [5, 104], "namespac": [5, 101, 105, 111, 112], "log": [5, 34, 55, 64, 83, 84, 91, 101, 114], "binaryoper": [5, 6, 104], "boundednumb": [5, 6, 104], "boxcar": [5, 6, 104], "exponentialdecai": [5, 6, 104], "normalrandom": [5, 6, 104], "numbergener": [5, 6, 104], "randomdistribut": [5, 6, 104], "scaledtim": [5, 6, 104], "squarewav": [5, 6, 104], "timesampledfn": [5, 6, 104], "unaryoper": [5, 6], "uniformrandom": [5, 6, 104], "uniformrandomoffset": [5, 6, 104], "vonmisesrandom": [5, 6, 104], "accord": 6, "distribut": [6, 33, 104, 108], "lh": 6, "rh": 6, "revers": [6, 111], "fals": [6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 36, 37, 38, 39, 40, 41, 42, 45, 47, 60, 65, 66, 70, 73, 82, 85, 86, 88, 93, 100, 104, 105, 108, 110, 111, 112], "arg": [6, 55, 63, 64, 69, 78, 81, 83, 84, 88, 101, 103, 106], "binari": [6, 9, 104, 112], "yield": 6, "silent": [6, 30, 101, 103, 104, 108, 112], "allow_non": [6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 33, 36, 37, 38, 39, 40, 41, 42, 93, 100, 101, 105, 108, 110, 112], "allow_ref": [6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 33, 36, 37, 38, 39, 40, 41, 42, 103], "label": [6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 33, 36, 37, 38, 39, 40, 41, 42, 101, 104, 108, 110], "nested_ref": [6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 33, 36, 37, 38, 39, 40, 41, 42], "rx": 6, "reactiv": [6, 114], "reactive_op": 6, "0x7f89343921f0": 6, "call": [6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 19, 20, 21, 22, 23, 24, 26, 27, 29, 33, 34, 35, 36, 38, 39, 40, 60, 66, 77, 82, 85, 88, 101, 103, 104, 106, 107, 108, 109, 110, 111, 112, 113], "none": [6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 33, 36, 37, 38, 39, 40, 41, 42, 48, 53, 57, 68, 70, 73, 74, 77, 88, 90, 92, 93, 100, 101, 103, 104, 105, 107, 108, 109, 110, 111, 112], "0x7f8934392c10": 6, "legal": [6, 30, 108], "pair": [6, 52, 60, 82, 101, 108, 110, 112], "One": [6, 30, 103, 108, 112], "lower": [6, 30, 48, 85, 88, 103, 108, 110], "upper": [6, 30, 48, 104, 108], "durat": [6, 104], "onset": [6, 104], "time_depend": [6, 19, 104], "time_fn": [6, 19, 77, 104], "timedepend": 6, "interv": [6, 104, 108], "exclus": [6, 30, 104, 108], "zero": [6, 104], "offset": [6, 104], "around": [6, 104, 108, 112], "en": 6, "wikipedia": 6, "wiki": 6, "boxcar_funct": 6, "timeawar": 6, "inclusive_bound": [6, 11, 17, 25, 28, 30, 37, 93, 100, 108, 112], "0x7f8934554610": 6, "0x7f8934554460": 6, "seed": [6, 101, 104], "random_gener": [6, 104], "element": [6, 11, 17, 31, 37, 41, 42, 108, 111], "item": [6, 26, 32, 53, 56, 60, 71, 72, 85, 88, 101, 102, 103, 108, 110, 112], "further": [6, 102, 104, 108, 110, 111, 113], "timeawarerandomst": [6, 101, 104], "0x7f8934554e20": 6, "select": [6, 13, 21, 29, 38, 101, 103, 108, 112], "ending_valu": [6, 104], "starting_valu": [6, 104], "time_const": [6, 104], "decai": 6, "exponenti": 6, "exponential_decai": 6, "0x7f893457ef10": 6, "end": [6, 17, 33, 103, 106], "0x7f89344ef910": 6, "infin": 6, "10000": [6, 104], "0x7f893457e820": 6, "scale": [6, 102], "slow": [6, 101, 102, 105, 106], "718281828459045": 6, "expon": 6, "exp": 6, "anoth": [6, 103, 104, 105, 106, 107, 110, 111, 112], "popular": 6, "interpret": 6, "mu": [6, 104], "sigma": [6, 33, 104], "gaussian": [6, 104], "deviat": [6, 33, 104], "0x7f89344d56d0": 6, "0x7f89344d5bb0": 6, "abstract": [6, 44, 101, 105, 108, 109], "produc": [6, 19, 104, 106], "primarili": [6, 65, 69, 108, 111, 112], "x": [6, 42, 101, 103, 104, 105, 108, 110], "y": [6, 42, 105, 108, 110], "z": [6, 108], "hierarchi": [6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 101, 108, 110, 111], "easier": [6, 86, 103, 108, 109, 113], "ti": [6, 103, 111], "particular": [6, 103, 104, 105, 107, 108, 110, 111, 112, 113], "pass": [6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 101, 103, 104, 111, 112], "pickl": [6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 104, 105, 108, 114], "lock": 6, "desir": [6, 101, 102, 106, 107, 110, 112], "By": [6, 13, 19, 38, 51, 65, 69, 85, 103, 104, 106, 108, 110, 112], "obtain": [6, 35, 63, 103, 108, 112], "reproduc": [6, 101, 104], "move": [6, 112, 113], "forward": [6, 108], "backward": [6, 78, 101, 104], "test": [6, 15, 101, 102, 104, 106, 108, 111, 113], "0x7f89345385e0": 6, "factor": [6, 104], "multipli": [6, 103, 109, 110, 111], "convers": [6, 20, 103, 108, 112], "0x7f89344cf760": 6, "off_dur": [6, 104], "squar": 6, "wave": 6, "period": [6, 104], "off": [6, 104, 112], "portion": 6, "spent": 6, "high": [6, 103, 108], "match": [6, 10, 21, 29, 32, 34, 40, 101, 108, 111, 112, 113], "low": [6, 103, 108, 111], "duti": [6, 104], "cycl": [6, 104], "50": [6, 104, 108, 110, 112], "begin": [6, 33], "after": [6, 11, 17, 31, 37, 41, 42, 88, 92, 101, 102, 103, 106, 108, 110], "0x7f893452c7c0": 6, "rel": [6, 22, 23, 36, 105, 106, 108, 113], "0x7f893452c490": 6, "dure": [6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 85, 88, 101, 103, 108, 110, 112], "0x7f893452c820": 6, "fn": [6, 85, 86, 88, 103, 104], "sampl": [6, 104], "regular": [6, 10, 12, 40, 101, 105, 108, 110, 111], "held": [6, 104], "within": [6, 30, 46, 103, 108, 110], "0x7f89344c0910": 6, "softbound": [6, 11, 17, 25, 28, 30, 37, 48, 101, 108], "0x7f89345f2e80": 6, "drawn": [6, 108], "0x7f89344c0d30": 6, "operand": [6, 111], "unari": [6, 104], "lbound": [6, 104], "0x7f8934547580": 6, "inclus": [6, 30, 104, 108], "0x7f89345f2160": 6, "0x7f8934547460": 6, "1000": [6, 104, 113], "0x7f893454e1c0": 6, "ident": [6, 108, 110, 111], "0x7f89344049a0": 6, "0x7f8934404be0": 6, "maximum": [6, 26, 112], "minimum": [6, 26, 112], "kappa": [6, 104], "circularli": [6, 104], "uniform": [6, 104], "angl": 6, "pi": [6, 104, 110], "otherwis": [6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 21, 22, 23, 24, 26, 27, 29, 31, 32, 33, 36, 37, 38, 39, 40, 41, 42, 48, 52, 104, 105, 107, 108, 112], "concentr": 6, "greater": 6, "lesser": 6, "degre": 6, "determin": [6, 11, 17, 31, 37, 41, 42, 65, 69, 85, 88, 101, 103, 104, 105, 108, 110, 112], "narrow": [6, 104], "peak": 6, "varianc": [6, 104], "0x7f8934409940": 6, "283185307179586": 6, "0x7f8934409b80": 6, "invers": [6, 104], "preced": [7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 33, 36, 37, 38, 39, 40, 41, 42, 85, 86, 88, 101, 103, 105, 110, 113], "readonli": [7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 33, 36, 37, 38, 39, 40, 41, 42, 105, 108, 110], "pickle_default_valu": [7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 33, 36, 37, 38, 39, 40, 41, 42, 105, 112], "per_inst": [7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 33, 36, 37, 38, 39, 40, 41, 42, 105, 110], "invok": [7, 35, 45, 85, 86, 88, 101, 103, 104, 105, 107, 108, 109, 111, 113], "might": [7, 12, 105, 106, 109, 110, 111, 112, 113], "button": [7, 103, 108, 111], "directli": [7, 20, 63, 103, 104, 106, 107, 109, 110, 113], "__init__": [7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 53, 88, 103, 104, 105, 110, 112, 113], "store": [7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 33, 36, 38, 39, 40, 101, 103, 104, 105, 108, 110, 112], "own": [7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 53, 88, 101, 102, 104, 105, 106, 108, 110, 112], "repres": [7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 53, 93, 100, 108, 112], "overridden": [7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 32, 33, 36, 38, 39, 40, 112], "docstr": [7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 101, 104, 105, 108, 110, 113], "text": [7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 112, 113, 114], "shown": [7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 109, 110], "menu": [7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40], "neg": [7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 85, 103, 108], "should": [7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 54, 77, 101, 102, 103, 104, 108, 110, 111, 112, 113], "hidden": [7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40], "deepcopi": [7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 110], "immut": [7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 110], "best": [7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 104, 112], "affect": [7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 101, 102, 103, 105, 110], "futur": [7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 77, 101, 103, 104, 110], "mutabl": [7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 103, 110], "refer": [7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 45, 101, 103, 108, 110, 111], "singleton": [7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40], "construct": [7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 34, 36, 38, 39, 40, 101, 106, 108, 109, 112], "ordinarili": [7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 111], "temporarili": [7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 47, 81, 91, 106, 110], "overrid": [7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 32, 33, 34, 36, 38, 39, 40, 49, 51, 101, 103, 104, 105, 110, 111, 112], "slot": [7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 53, 85, 88, 101, 103], "restor": [7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 101, 103, 104, 105, 110, 112], "_user_": [7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40], "never": [7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 102, 103, 104, 111, 112], "execut": [7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 85, 88, 101, 103, 104, 105, 106, 108, 110, 111, 112], "would": [7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 101, 102, 104, 105, 106, 107, 109, 110, 111, 112, 113], "rare": [7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 102, 112, 113], "search": [7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 105, 108, 110], "path": [7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 38, 39, 40, 101, 103, 110, 112], "conceptu": [7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40], "similar": [7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 92, 101, 102, 104, 105, 108, 109, 110, 112], "addit": [7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 85, 101, 103, 104, 105, 106, 108, 109, 110, 111, 112], "reflect": [7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 111], "nest": [7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 101, 103, 112], "dictionari": [7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 32, 33, 36, 38, 39, 40, 44, 49, 52, 68, 81, 82, 87, 93, 100, 101, 103, 105, 106, 108, 110, 112], "slice": [7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40], "tupl": [7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 21, 22, 23, 24, 26, 27, 29, 31, 33, 36, 37, 38, 39, 40, 42, 49, 51, 67, 101, 103, 107, 112], "inspect": [7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 101, 103, 104, 110], "resolv": [7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 101, 103, 108], "parameterizedmetaclass": [7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 26, 27, 29, 33, 36, 38, 39, 40, 105], "is_inst": [8, 13, 16, 18, 39, 108], "whose": [8, 16, 18, 19, 20, 24, 26, 33, 38, 39, 103, 108, 110, 111, 112], "numpi": [8, 101, 104, 108, 111, 112], "tristat": 9, "regex": [10, 40, 108], "length": [11, 17, 26, 31, 37, 41, 42, 103, 108, 111], "date": [11, 17, 101, 108, 112], "start_dat": 11, "end_dat": 11, "fix": [11, 17, 31, 37, 41, 42, 101, 104, 105, 108, 111, 112, 113], "hold": [12, 103, 105], "keyword": [12, 33, 34, 49, 50, 51, 78, 81, 86, 88, 101, 103, 107, 109, 110, 111, 112], "standalon": [12, 33, 101, 103], "those": [12, 21, 33, 49, 63, 77, 85, 101, 103, 104, 105, 106, 108, 109, 110, 111, 112, 113], "class_": [13, 24, 26, 93, 100, 101, 103, 108, 110, 112], "either": [13, 16, 22, 23, 36, 38, 45, 53, 63, 85, 88, 101, 103, 104, 105, 108, 110, 111, 112, 113], "matter": [13, 104, 112], "allow_nam": [14, 108], "hex": [14, 108], "rgb": [14, 108], "prefix": [14, 34, 70, 92, 106, 108, 110, 112], "css3": 14, "attrib": 15, "kw": [15, 45, 51, 55, 63, 64, 83, 84, 101, 106], "constitu": 15, "likewis": 15, "sequenc": [15, 24, 108, 110], "watcher": [15, 20, 53, 79, 80, 85, 89, 101, 104, 105, 108, 110, 111, 114], "row": [16, 39, 103, 108, 112], "column": [16, 104, 108, 112], "panda": [16, 39, 101, 104, 108, 111, 112], "structur": [16, 39, 103, 105, 107, 111], "constrain": [16, 39, 108, 110], "semant": [16, 101, 104, 108, 111], "datetim": [17, 106, 108, 112], "dt_type": 17, "present": [19, 30, 32, 77, 107, 108], "product": [19, 102, 107], "last": [19, 52, 62, 101, 104, 112], "regardless": [19, 104], "manipul": 19, "intim": [20, 103], "trigger": [20, 46, 53, 85, 88, 89, 101, 108, 111, 114], "consum": [20, 102, 103], "boolean": [20, 36, 103, 111], "associ": [20, 33, 103, 105, 106, 110], "back": [20, 101, 103, 104, 113], "transient": [20, 103], "being": [20, 30, 53, 77, 92, 101, 103, 105, 106, 108, 112, 113], "watch": [20, 45, 53, 80, 86, 88, 101, 110], "momentari": [20, 103], "switch": [20, 101, 103, 104], "pushbutton": [20, 103], "serv": [20, 103], "launch": [20, 103], "action": [20, 101, 103, 107, 108, 111, 112], "encapsul": [20, 103], "compute_default_fn": [21, 27, 29, 38, 108], "check_on_set": [21, 27, 29, 38, 108], "empty_default": [21, 27, 29, 38], "glob": [21, 29, 108], "search_path": [22, 23, 36, 108], "check_exist": [22, 23, 36, 108], "unix": [22, 23, 36, 108], "style": [22, 23, 36, 101, 104, 106, 108, 111], "format": [22, 23, 34, 36, 51, 55, 63, 64, 83, 84, 101, 102, 108, 111, 112], "absolut": [22, 23, 36, 108], "resolve_path": [22, 36], "resolve_dir_path": 23, "item_typ": [24, 26, 101, 108, 112], "place": [24, 103, 108, 112], "regist": [24, 85, 103], "set_hook": [25, 28, 30], "against": [25, 28, 30, 101, 102, 108, 111, 113], "alia": [26, 106], "deprec": [26, 55, 56, 60, 64, 68, 71, 72, 76, 78, 83, 101, 102, 110, 112], "due": [26, 103, 105], "conflict": 26, "selector": [26, 27, 101, 103, 104, 105], "variant": [27, 92], "There": [30, 105, 108, 110, 113], "hard": [30, 48, 101, 103, 106, 108, 112], "set_in_bound": [30, 108], "crop": [30, 101, 104, 108], "soft": [30, 48, 101, 108], "slider": [30, 108], "distanc": [30, 113], "dict_": 32, "allow_extra_keyword": [32, 109], "kei": [32, 103, 110, 112], "warn": [32, 52, 63, 101, 112, 114], "print": [32, 34, 55, 63, 64, 70, 71, 72, 83, 84, 92, 101, 103, 106, 108, 110, 111, 112], "extra_keyword": [32, 109], "descriptor": [33, 109], "kind": [33, 110, 111], "caus": [33, 101, 106, 110, 112], "assign": [33, 102, 110], "suppos": 33, "foo": [33, 34], "bar": 33, "delta": 33, "alpha": 33, "gamma": 33, "she": 33, "her": 33, "advantag": [33, 104], "plain": 33, "arbitrari": [33, 103, 108, 111], "script": [33, 44, 92, 101, 112, 114], "myfoo": 33, "super": [33, 40, 103, 110, 112], "extern": [33, 103, 114], "enough": [33, 105], "sheet": 33, "graphic": 33, "edit": [33, 47, 92, 101, 108, 112], "messag": [34, 55, 63, 83, 84, 101, 113, 114], "design": [34, 92, 104, 111, 112], "consist": [34, 101, 102, 103, 106, 108], "uniqu": [34, 103, 104, 110], "digit": [34, 110], "xx": 34, "20": [34, 108, 111], "parameternam": 34, "parametervalu": 34, "append": [34, 103, 108, 110], "wrap": [34, 108, 111], "root": [34, 101], "logger": [34, 101, 106], "prepend": [34, 106], "act": [35, 109, 110, 111], "pleas": [36, 101, 103], "filenam": [36, 108], "foldernam": [36, 108], "discrimin": 36, "o": [36, 101, 103, 108, 110, 112], "getcwd": [36, 108], "pick": 38, "collect": [38, 77, 102, 105, 108, 110, 111, 112], "among": [38, 108], "wherea": [38, 104, 110], "unless": [38, 66, 84, 101, 106, 110, 111], "prefer": [38, 78], "hashabl": 38, "look": [38, 103, 108, 110, 112, 113], "intern": [38, 65, 69, 85, 92, 101, 103, 104, 106, 107, 110, 112, 114], "ipv4": 40, "ipaddress": 40, "dot": [40, 103], "decim": [40, 108], "notat": 40, "kwarg": [40, 50, 69, 78, 81, 88, 106, 110], "ip_regex": [40, 108], "r": [40, 101, 110], "25": [40, 106, 108, 112], "01": [40, 108], "numerictupl": [42, 108], "enabl": [43, 101, 103, 108, 112], "parentclass": 44, "caller": 44, "func": [45, 51], "subobject": [45, 77, 101, 103, 104, 110], "bool": [45, 52], "context": [46, 81, 89, 101, 103, 104, 106, 110], "discard": [46, 103, 106, 112], "event": [46, 79, 85, 86, 88, 89, 101, 104, 108, 111, 114], "scope": [46, 103], "equal": [48, 60, 82, 101], "exce": 48, "correspond": [49, 78, 81, 101, 103, 110, 111, 112, 113], "copi": [49, 101, 103, 105, 108, 110, 112, 113], "liter": 50, "promot": 50, "heurist": 50, "queri": [51, 107, 108], "custom": [51, 101, 104, 108, 110, 112, 113], "guarante": [51, 92, 107, 112, 113], "custom_nam": 51, "upgrad": [51, 107], "classselector": [51, 101, 103, 107, 110, 112], "int": [51, 93, 100, 107, 108, 111, 112, 113], "union": 52, "wether": 52, "dict": [52, 60, 101, 108, 110, 112], "obj": [53, 93, 100, 103, 104, 105, 108, 110], "cl": [53, 71, 88, 103], "old": [53, 101, 103, 106, 112], "previou": [53, 101, 103, 111, 112], "onlychang": [53, 60, 82, 85, 86, 88, 103, 110], "yet": [53, 101, 102, 103, 108, 113], "known": [53, 108], "param_nam": [54, 76, 79, 86, 88, 103, 110], "param_obj": [54, 110], "msg": [55, 63, 64, 83, 84, 106], "merg": [55, 63, 64, 83, 84, 101, 102, 106], "statement": [55, 92, 111, 112, 113], "sinc": [55, 56, 60, 64, 66, 68, 71, 72, 76, 78, 83, 101, 103, 104, 105, 106, 108, 110, 111, 112], "12": [55, 56, 60, 64, 68, 71, 72, 76, 78, 83, 104, 108], "parameter_nam": [56, 68, 85, 86, 88, 103], "k": [56, 71, 72, 101, 104], "v": [56, 71, 72, 101, 104, 108, 114], "p": [56, 71, 72, 76, 93, 100, 101, 103, 104, 105, 107, 108, 109, 110, 111, 112], "subset": [57, 73, 74, 93, 100, 108, 112], "mode": [57, 58, 73, 74, 75, 88, 101, 103, 104], "pname": [58, 75, 93, 100], "forc": [59, 66, 103, 108], "getattr": [59, 61, 62], "common": [60, 101, 106, 108, 110, 113], "debug": [63, 101, 105, 106], "critic": [63, 101, 106], "intermedi": [65, 69, 106], "pinfo": [65, 69, 88, 103], "content": [65, 69, 85, 103, 110], "sub": [65, 69, 103], "necessari": [66, 110], "index": [67, 103, 107], "parameter_object": 68, "unknown_valu": [70, 92, 104, 112], "qualifi": [70, 92, 112], "experiment": 70, "pretti": [70, 92, 101, 110], "represent": [70, 92, 101, 106, 110, 112], "eval": 70, "f": [71, 72, 101, 103, 106, 108, 110, 111, 112, 113], "__class__": [71, 72, 101], "repr": [71, 72, 101, 103], "safe": [73, 93, 100, 107, 110, 111, 112, 113], "sublistattr": 77, "addition": [77, 103], "_dynamic_time_fn": 77, "parmet": 77, "iter": [77, 81, 103, 104, 106, 110, 111], "too": [77, 101, 110], "compat": [78, 101, 104], "posit": [78, 85, 88, 101, 103, 104, 107, 108, 109, 110, 111, 112], "compact": [78, 112], "remov": [80, 101, 102, 103, 110, 113], "watch_valu": [80, 88, 103], "reset": [81, 104], "variabl": [84, 106, 111, 113], "warnings_as_except": [84, 106], "rais": [84, 102, 106, 108, 110, 112, 113, 114], "queu": [85, 86, 88, 103], "callback": [85, 86, 88, 101, 103, 111], "els": [85, 103, 105, 108, 111, 113], "again": [85, 101, 104, 107, 108, 111, 112], "insid": [85, 101, 106, 110, 112], "dispatch": [85, 89, 103], "depth": [85, 103], "howev": [85, 101, 104, 105, 108, 109, 111, 112], "scenario": 85, "wait": [85, 103], "downstream": [85, 111], "until": [85, 101, 103, 108, 110, 111], "queue": [85, 88, 89], "finish": [85, 111], "breadth": [85, 103], "prioriti": [85, 88, 103], "earlier": [85, 102, 103, 110], "reserv": [85, 103, 105, 110], "relev": [85, 106], "occur": [85, 106], "new_valu": [86, 88, 103], "inst": [88, 103], "later": [88, 101, 103, 105, 108, 112, 113], "higher": [88, 103, 104], "save": [89, 92, 104, 105, 110, 112, 114], "exit": [89, 103, 110], "n": [92, 103, 108, 110, 112], "show_import": [92, 112], "pprint": [92, 101, 104, 110], "runnabl": [92, 112], "parameterized_obj": 92, "meant": [92, 101, 103, 108, 110], "py": [92, 101, 103, 110, 112], "Not": [92, 112], "good": [92, 103, 110], "point": [92, 110, 111, 112], "minor": [92, 101, 102], "newli": 92, "apart": [92, 101, 103, 110, 111, 112], "explan": 92, "prompt": [92, 103, 104, 112], "These": [93, 95, 103, 104, 106, 111], "jsonnul": [93, 100], "json_typ": [93, 100], "schema": [93, 100, 101], "nullabl": [93, 100, 110], "jsonseri": [93, 100], "respons": [93, 100, 103, 104], "deseri": [93, 100, 112], "classmethod": [93, 100, 103], "array_schema": [93, 100], "calendardate_schema": [93, 100], "class__schema": [93, 100], "classselector_schema": [93, 100], "dataframe_schema": [93, 100], "date_schema": [93, 100], "declare_numeric_bound": [93, 100], "augment": [93, 100], "deserialize_parameter_valu": [93, 100], "pobj": [93, 100, 103], "deserialize_paramet": [93, 100, 112], "dict_schema": [93, 100], "dump": [93, 100, 101, 112], "integer_schema": [93, 100], "json_schema_literal_typ": [93, 100], "nonetyp": [93, 100], "null": [93, 100, 112], "list_schema": [93, 100], "listselector_schema": [93, 100], "number_schema": [93, 100], "numerictuple_schema": [93, 100], "objectselector_schema": [93, 100], "param_schema": [93, 100], "ptype": [93, 100], "range_schema": [93, 100], "selector_schema": [93, 100], "serialize_parameter_valu": [93, 100], "serialize_paramet": [93, 100, 112], "tuple_schema": [93, 100], "unserializable_parameter_typ": [93, 100], "xycoordinates_schema": [93, 100], "unsafeserializableexcept": [93, 100, 112], "unserializableexcept": [93, 100], "2023": [101, 106, 108, 112], "14": [101, 104, 110, 112], "befor": [101, 106, 108, 110, 111, 112], "receiv": [101, 108, 113], "secur": 101, "patch": 101, "plan": [101, 102], "backport": 101, "seri": [101, 103, 104, 108, 112], "byte": [101, 112], "few": [101, 110, 111, 112], "mark": [101, 103], "adopt": 101, "formal": [101, 104], "govern": 101, "ensur": [101, 103, 108, 112, 113], "healthi": 101, "ovidn": 101, "droumi": 101, "contribut": 101, "And": [101, 105], "maximlt": 101, "hoxbro": 101, "jlsteven": 101, "philippjfr": 101, "jbednar": 101, "continu": [101, 103, 104, 106, 110, 113], "675": 101, "655": 101, "listselector": [101, 108], "531": 101, "async": 101, "wrapper": [101, 104, 108], "684": 101, "color": [101, 111], "711": 101, "542": 101, "682": 101, "674": 101, "mainten": 101, "renam": [101, 112], "master": 101, "branch": 101, "main": [101, 103, 106, 110, 111, 112], "672": 101, "710": 101, "ci": [101, 106], "relat": [101, 108, 113], "680": 101, "683": 101, "709": 101, "2022": [101, 108], "musicinmybrain": 101, "enhanc": 101, "preserv": [101, 104], "638": 101, "658": 101, "unfortun": [101, 113], "longer": [101, 103, 108, 110, 111, 112], "drop": [101, 103], "announc": 101, "spec": 101, "615": 101, "python2": 101, "syntax": [101, 105, 111], "624": 101, "de": 101, "calendarrang": 101, "daterang": [101, 108], "625": 101, "627": 101, "regress": 101, "628": 101, "named_obj": 101, "fail": [101, 112], "unhash": 101, "632": 101, "629": 101, "binarypow": 101, "eveninteg": [101, 110], "634": 101, "descript": [101, 112], "shared_paramet": [101, 110], "568": 101, "579": 101, "clarifi": 101, "604": 101, "iscoroutinefunct": 101, "572": 101, "misspel": 101, "575": 101, "calendard": [101, 108], "arrai": [101, 104, 108, 112], "datafram": [101, 104, 108, 111, 112], "582": 101, "coroutin": [101, 103], "591": 101, "611": 101, "612": 101, "binder": 101, "564": 101, "introduc": [101, 111, 113], "manual": [101, 103, 108, 110, 112, 113], "along": [101, 103, 104], "api": [101, 102, 103, 108, 111], "gear": 101, "python3": [101, 103, 106], "older": [101, 112], "next": [101, 102, 103], "expect": [101, 102, 108, 110, 112, 113], "pin": 101, "go": [101, 105, 112], "jame": 101, "bednar": 101, "philipp": 101, "rudig": 101, "capabl": [101, 104, 110, 112], "maxim": 101, "liquet": 101, "face": [101, 111], "556": 101, "558": 101, "559": 101, "540": 101, "replac": [101, 103], "552": 101, "prettyprint": 101, "525": 101, "458": 101, "script_repr": 101, "availabi": 101, "522": 101, "interact": [101, 103, 104, 110, 112], "557": 101, "544": 101, "511": 101, "getargspec": 101, "py3": 101, "getfullargspec": 101, "split": 101, "varkw": 101, "fall": 101, "521": 101, "misc": 101, "comment": 101, "cleanup": 101, "507": 101, "518": 101, "528": 101, "553": 101, "comparison": [101, 112], "523": 101, "dependencies_and_watch": 101, "536": 101, "persist": [101, 102, 105, 110, 114], "infrastructur": 101, "mac": 101, "548": 101, "549": 101, "526": 101, "509": 101, "529": 101, "530": 101, "537": 101, "538": 101, "539": 101, "547": 101, "555": 101, "543": 101, "517": 101, "No": 101, "confus": [101, 110, 113], "541": 101, "_add_paramet": 101, "add_paramet": [101, 110], "privat": [101, 105, 110], "params_depended_on": 101, "method_depend": [101, 103], "_pprint": 101, "batch_watch": 101, "batch_call_watch": 101, "unus": 101, "repurpos": 101, "delet": [101, 112], "print_param_default": 101, "print_param_valu": 101, "set_default": 101, "set_param": 101, "had": [101, 103, 112], "tricki": 101, "get_param_valu": 101, "state_pop": 101, "Will": 101, "_state_pop": 101, "state_push": 101, "_state_push": 101, "_initi": 101, "accessor": [101, 105, 110], "_watcher": 101, "subsum": 101, "legaci": 101, "functionailti": 101, "entir": [101, 106, 110, 112], "bugfixess": 101, "setup": [101, 103], "brand": 101, "428": 101, "464": 101, "479": 101, "483": 101, "501": 101, "502": 101, "503": 101, "504": 101, "promo": 101, "ipynb": [101, 108], "marc": 101, "skov": 101, "madsen": 101, "egbert": 101, "ammicht": 101, "488": 101, "andrew": 101, "huang": 101, "445": 101, "recurs": [101, 110], "499": 101, "472": 101, "fileselector": [101, 108], "multifileselector": [101, 108], "497": 101, "simon": 101, "hansen": 101, "467": 101, "476": 101, "475": 101, "previous": [101, 103, 112], "495": 101, "unimpl": 101, "_on_set": 101, "484": 101, "ipython": [101, 110, 111], "477": 101, "473": 101, "474": 101, "repo": 101, "port": 101, "autov": 101, "pull": [101, 102, 103, 104], "67": 101, "469": 101, "swap": 101, "objectselector": [101, 108], "get_soft_bound": [101, 108], "498": 101, "clash": [101, 110, 111], "456": 101, "bugfix": 101, "446": 101, "asynchron": [101, 103], "executor": 101, "449": 101, "450": 101, "get_rang": [101, 108], "360": 101, "eager": 101, "351": 101, "calendar": 101, "calendardaterang": [101, 108], "real": [101, 110, 113], "348": 101, "334": 101, "truthi": 101, "337": 101, "mix": 101, "338": 101, "dt": 101, "341": 101, "aren": 101, "343": 101, "per": 101, "306": 101, "319": 101, "326": 101, "keywords_to_param": 101, "util": [101, 103, 110], "deduc": 101, "317": 101, "312": 101, "friendli": 101, "316": 101, "330": 101, "selectorbas": [101, 108], "320": 101, "323": 101, "327": 101, "329": 101, "315": 101, "325": 101, "299": 101, "q": [101, 103, 107, 110, 111, 112], "unwatch": [101, 103], "268": 101, "285": 101, "241": 101, "245": 101, "cleaner": 101, "230": 101, "dev": 101, "223": 101, "cfg": 101, "49": 101, "234": 101, "225": 101, "39": [101, 110, 111, 112], "dirti": 101, "41": [101, 104], "failur": 101, "commit": 101, "count": [101, 103, 104, 105], "44": [101, 104], "notabl": 101, "__version__": 101, "tag": [101, 102], "workflow": 101, "175": 101, "attempt": [101, 102, 110], "cython": 101, "166": 101, "194": 101, "162": 101, "incorrect": [101, 113], "151": 101, "104": 101, "compute_default": [101, 108], "212": 101, "208": 101, "__nonzero__": 101, "__len__": 101, "miscellan": 101, "218": 101, "paramoverrid": [101, 109], "paramnb": 101, "unicod": 101, "accident": 101, "therefor": [101, 103, 111], "lazi": [101, 106], "foreign": 101, "marco": 101, "elver": 101, "topographica": [101, 104], "heavi": 101, "matur": 102, "slowli": 102, "undertaken": 102, "signific": [102, 110], "attent": [102, 112], "progress": [102, 106], "hope": 102, "schedul": [102, 103], "2020": 102, "power": [102, 103, 104, 105, 110, 111, 114], "414": 102, "lumen": 102, "great": [102, 111], "integr": [102, 106], "id": [102, 103], "interoper": 102, "swagger": 102, "openapi": 102, "convert": [102, 108, 111, 112], "editor": 102, "linter": 102, "optim": [102, 105], "pep8": 102, "strictli": 102, "wasn": 102, "mind": [102, 112], "badli": 102, "But": [102, 103, 104, 111, 112, 113], "black": 102, "triag": 102, "team": 102, "volunt": 102, "explic": 102, "task": [102, 103, 113], "experienc": 102, "coverag": 102, "mileston": 102, "wishlist": 102, "person": 102, "agre": 102, "encourag": 102, "core": [102, 105], "intent": 102, "outlin": 103, "chain": [103, 104, 107], "driven": [103, 104], "push": [103, 104], "calcul": [103, 104, 108], "spawn": 103, "cascad": 103, "adapt": [103, 104], "contrast": [103, 113], "clock": [103, 104], "learn": 103, "three": [103, 104, 113], "interlink": 103, "relationship": [103, 114], "_countri": 103, "africa": 103, "ghana": 103, "togo": 103, "south": 103, "asia": 103, "china": 103, "thailand": 103, "japan": 103, "singapor": 103, "europ": 103, "austria": 103, "bulgaria": 103, "greec": 103, "switzerland": 103, "contin": [103, 110], "countri": [103, 110], "_update_countri": 103, "c00002": 103, "whenev": [103, 104, 108, 109, 111], "sure": [103, 105, 108, 110, 112, 113], "kept": 103, "inconsist": 103, "final": 103, "direct": 103, "ll": [103, 104, 105, 108, 109, 110, 111, 112], "importantli": [103, 111, 113], "ourselv": 103, "brittl": 103, "handler": 103, "strategi": 103, "elsewher": 103, "__slots__": [103, 105], "break": 103, "chunk": 103, "prerequisit": 103, "everyth": 103, "d": [103, 106, 108, 110, 111, 112, 113], "red": [103, 108, 111], "green": [103, 108], "blue": [103, 108], "cb1": 103, "cb2": 103, "cb3": 103, "cb4": 103, "d00003": 103, "verifi": 103, "examin": 103, "twice": [103, 111], "rebind": 103, "c00004": 103, "fire": 103, "connect": [103, 107, 112, 114], "holoview": 103, "side": [103, 109], "effecti": 103, "consid": [103, 105], "mul": 103, "100": [103, 104, 108], "view": 103, "view2": 103, "prod": [103, 107], "70": [103, 104, 109], "Or": [103, 104], "pn": 103, "home": [103, 108], "runner": [103, 108], "env": 103, "virtual": 103, "vefsptnl": 103, "lib": [103, 108], "viewabl": 103, "298": 103, "paramfuturewarn": 103, "pane": 103, "panebas": 103, "implicitli": 103, "live": [103, 111], "html": [103, 110], "export": [103, 112], "page": [103, 105, 107, 108], "abl": [103, 108, 110, 111, 112], "told": [103, 105], "ask": 103, "omit": [103, 112], "conserv": 103, "assum": [103, 112, 114], "Be": [103, 112], "bare": 103, "cb": 103, "usa": 103, "respond": 103, "delai": [103, 110], "run_a1": 103, "run_a2": 103, "run_b": 103, "a1": [103, 104, 105], "a2": [103, 104, 105], "try": [103, 111, 112], "similarli": [103, 108, 112], "accumul": 103, "elid": 103, "writabl": 103, "circuit": 103, "8": [103, 104, 108, 109, 111, 113], "_parametersrestor": 103, "0x7f471c62ce80": 103, "phase": 103, "care": [103, 112], "notic": [103, 104, 110, 112], "despit": 103, "advanc": [103, 104], "p00180": 103, "__main__": [103, 108, 112], "block": 103, "asyncio": 103, "await": 103, "async_executor": 103, "loop": [103, 112], "tornado": 103, "ioloop": 103, "aiohttp": 103, "add_callback": 103, "fetch": 103, "clientsess": 103, "session": [103, 108, 112], "img": 103, "picsum": 103, "photo": 103, "800": 103, "300": 103, "imag": [103, 104], "cell": [103, 111, 113], "repeatedli": [103, 108], "ed": 103, "image_nam": 103, "image_data": 103, "internet": 103, "len": 103, "05": [103, 106], "sequenti": 103, "find": [103, 112], "idea": [103, 113], "down": [103, 106, 113], "decoupl": 103, "peopl": 103, "cover": [103, 108, 110, 112], "fanci": [104, 113], "a3": 104, "disadvantag": 104, "situat": [104, 105, 110], "understand": [104, 105, 106, 112], "third": [104, 111], "nice": 104, "j": 104, "p00002": [104, 107], "illustr": 104, "35": 104, "99": 104, "0x7f5b5ceb3550": 104, "p00003": [104, 110], "0x7f5b5ceb3040": 104, "64": 104, "94": 104, "43": [104, 110, 111], "743899585374881": 104, "09120587218600318": 104, "7089640882129363": 104, "inspect_valu": [104, 110], "_count": [104, 105], "somewhat": 104, "train": 104, "anneal": 104, "central": 104, "45": 104, "increment": [104, 108], "81": 104, "72": 104, "90": 104, "conveni": [104, 105, 106, 108, 110, 111], "136": 104, "356": 104, "disrupt": [104, 113], "lot": [104, 105, 110], "set_dynamic_time_fn": 104, "engin": 104, "phenomena": 104, "discret": 104, "timebas": 104, "unnam": [104, 112], "cloudpickl": 104, "altern": [104, 105], "somewher": 104, "track": [104, 106, 111, 113], "prone": 104, "compos": 104, "interchang": [104, 112], "seamlessli": [104, 105], "tempor": 104, "moreov": [104, 110], "amount": [104, 113], "neatli": 104, "doubl": [104, 108], "basic": [104, 113], "reason": [104, 110, 112, 113], "roll": 104, "frequenc": 104, "demonstr": 104, "pd": [104, 108, 111, 112], "timesampl": 104, "ss": [104, 110], "df": [104, 108, 111, 112], "set_capt": 104, "nbsp": [104, 111], "000000": [104, 111], "16": 104, "18": [104, 111], "500000": [104, 111], "250000": 104, "125000": 104, "062500": 104, "031250": 104, "015625": 104, "007812": 104, "003906": 104, "001953": 104, "pseudorandom": 104, "ahead": 104, "repeat": 104, "overal": 104, "random_se": 104, "platform": 104, "hash": [104, 105], "substitut": [104, 106], "randomst": 104, "perform": [104, 105, 111], "center": 104, "uniformli": 104, "951541": 104, "623381": 104, "871864": 104, "988104": 104, "048456": 104, "473305": 104, "670172": 104, "976145": 104, "352763": 104, "073987": 104, "032228": 104, "352862": 104, "975963": 104, "98": 104, "507375": 104, "101": 104, "454955": 104, "043807": 104, "292438": 104, "832103": 104, "874644": 104, "390498": 104, "859": 104, "254": 104, "608": 104, "379": 104, "141": 104, "735": 104, "821": 104, "57": 104, "409": 104, "95": 104, "100000": [104, 111], "48": 104, "594489": 104, "47": 104, "525605": 104, "51": 104, "649262": 104, "42": [104, 108, 110, 111], "704838": 104, "365839": 104, "38": [104, 111], "123084": 104, "515447": 104, "410567": 104, "53": 104, "177450": 104, "56": 104, "113971": 104, "500": [104, 108], "small": [104, 113], "aka": [104, 106], "2pi": 104, "009431": 104, "253364": 104, "005742": 104, "283048": 104, "033316": 104, "266198": 104, "250874": 104, "024063": 104, "234760": 104, "223010": 104, "coupl": [104, 110], "filter": 104, "122012": 104, "167396": 104, "195102": 104, "029698": 104, "058429": 104, "144228": 104, "013971": 104, "170324": 104, "168170": 104, "096172": 104, "93": 104, "9614164612777242": 104, "4729860797140646": 104, "7161196189622282": 104, "decis": 104, "free": [104, 108], "imagen": 104, "richer": 105, "natur": [105, 111], "wonder": [105, 106], "especi": 105, "processor": 105, "answer": [105, 106, 110], "tailor": 105, "sophist": 105, "materi": 105, "successfulli": [105, 112], "hood": 105, "__get__": 105, "__set__": 105, "briefli": 105, "objtyp": 105, "rich": [105, 109, 110, 112], "expens": [105, 111, 113], "memori": [105, 110, 112], "__dict__": 105, "struct": 105, "space": 105, "instantan": [105, 112], "tabl": [105, 110], "storag": 105, "__getstate__": [105, 112], "__setstate__": [105, 112], "owner": 105, "_label": 105, "speed": 105, "unnecessari": 105, "parametermetaclass": 105, "fairli": [105, 112], "mainli": 105, "someparam": 105, "essenti": 105, "behind": [105, 111], "scalar": 105, "wipe": 105, "popul": 105, "ignor": [105, 112, 113], "bookkeep": 105, "parameterizedclass": 105, "fit": [105, 108], "_param__priv": [105, 110], "immun": 105, "left": [105, 109], "understood": 105, "redirect": 106, "cookbook": 106, "onscreen": 106, "sometim": 106, "fatal": 106, "eventu": [106, 113], "welcom": 106, "02d": 106, "02": 106, "discourag": 106, "frequent": 106, "render": [106, 111], "drastic": 106, "slowdown": 106, "isn": [106, 112], "greatli": [106, 113], "defer": 106, "awkward": 106, "highli": [106, 112, 113], "recommend": 106, "logging_level": 106, "elev": 106, "perman": 106, "get_logg": 106, "setlevel": 106, "encount": [106, 112], "hook": 106, "dai": 106, "dbprint_prefix": 106, "09": [106, 108, 112], "19": [106, 111, 112], "54": 106, "521876": 106, "522554": 106, "abort": 106, "miss": 106, "lost": 106, "sea": 106, "warning_count": 106, "At": [107, 108], "boxflow": 107, "dataflow": 107, "multi": 107, "0x7f881047cac0": 107, "form": [107, 108, 111, 112], "autom": [107, 112], "decid": 107, "review": 107, "commonli": [107, 110], "product2": 107, "prod_num": 107, "prod_str": 107, "int_product": 107, "q00003": 107, "0x7f88081c8280": 107, "0x7f88086d0250": 107, "0x7f881354a720": 107, "0x7f88081c81c0": 107, "0x7f88081c8340": 107, "0x7f8810483180": 107, "larger": 107, "alon": 108, "ship": 108, "predefin": [108, 114], "organ": 108, "concret": [108, 110, 111], "xycoordin": 108, "plane": 108, "min": 108, "max": 108, "hooklist": [108, 112], "stage": 108, "posix": 108, "composit": 108, "settabl": 108, "group": 108, "categori": 108, "exceptions_summar": [108, 110, 112, 113], "feel": 108, "score": 108, "forev": 108, "spade": 108, "email_regex": 108, "za": 108, "z0": 108, "_": 108, "ip_address": 108, "192": 108, "email": 108, "me": 108, "gmail": 108, "lemonchiffon": 108, "eeff00": 108, "puce": 108, "abcdefg": 108, "datetime64": 108, "suggest": 108, "granular": 108, "conform": 108, "dial": 108, "crop_to_bound": 108, "75": 108, "1900": 108, "fromisoformat": 108, "2002": 108, "25t00": 108, "00": 108, "2000": 108, "2d": 108, "draw": 108, "1910": 108, "31": 108, "1905": 108, "1907": 108, "min_length": 108, "max_length": 108, "empti": [108, 112], "intend": [108, 110], "algorithm": 108, "l": [108, 110, 112], "typeerror": [108, 110, 113], "multi_stage_exampl": 108, "h": 108, "v_": 108, "ex": 108, "m": [108, 112], "math": 108, "fab": 108, "116": 108, "slash": 108, "charact": 108, "retriev": 108, "filesystem": 108, "ioerror": 108, "parameter_typ": 108, "usr": 108, "csv": [108, 111], "user_guid": 108, "oserror": 108, "w": 108, "awesom": 108, "That": [108, 111, 112], "subsequ": [108, 110], "analog": 108, "yellow": 108, "gconf": 108, "imagemagick": 108, "packagekit": 108, "introspect": 108, "__abstract": 108, "e_inst": 108, "zerodivisionerror": 108, "arithmeticerror": 108, "e_class": 108, "overflowerror": 108, "ordereddict": 108, "floatingpointerror": 108, "decimalexcept": 108, "divisionbyzero": 108, "divisionundefin": 108, "clamp": 108, "round": 108, "inexact": 108, "subnorm": 108, "floatoper": 108, "invalidoper": 108, "underflow": 108, "overflow": 108, "conversionsyntax": 108, "divisionimposs": 108, "invalidcontext": 108, "ndarrai": [108, 112], "appear": [108, 112], "np": [108, 111, 112], "nan": [108, 111], "travers": 108, "upward": 108, "downward": 108, "usefulli": 108, "subtyp": [108, 110], "deriv": 108, "loos": 108, "setstat": 108, "getstat": [108, 112], "individu": [108, 112], "print_time_of_dai": 108, "todai": 108, "transform": 108, "substitu": 109, "21": 109, "realli": 109, "beyond": [109, 112, 113], "grab": 109, "multiply_by_10": 109, "80": 109, "visibl": 110, "contract": 110, "convent": [110, 112], "capit": [110, 112], "hasn": 110, "edit_const": 110, "mostli": 110, "meaning": 110, "ultimate_answ": 110, "meanwhil": 110, "0x7f54accc3180": 110, "involv": [110, 112, 113], "30": [110, 112, 113], "worri": 110, "sit": 110, "happili": [110, 113], "84": 110, "who": 110, "overidden": 110, "read_onli": 110, "overrod": 110, "suffix": 110, "consol": 110, "thing": [110, 112], "s1": 110, "s2": 110, "luckili": 110, "cost": 110, "prevent": 110, "saw": 110, "rule": 110, "thumb": 110, "aris": 110, "distinct": 110, "clobber": 110, "d1": 110, "d2": [110, 112], "lazili": 110, "e1": 110, "e2": 110, "pie": 110, "overhead": 110, "effici": 110, "sai": [110, 111], "speedup": 110, "__str__": 110, "concis": 110, "__repr__": 110, "classnam": 110, "parameter1": 110, "parameter2": 110, "_repr_html_": 110, "customiz": 110, "hierarch": 110, "demo": 110, "q00034": 110, "parameterized00035": 110, "p00033": 110, "parameterized00038": 110, "namevaluetyperang": 110, "x27": 110, "namedefaulttyperang": 110, "q00031": 110, "parameterized00032": 110, "circular": 110, "ellipsi": 110, "evolv": 110, "footprint": 110, "risk": 110, "clean": 110, "disambigu": 110, "_param__paramet": 110, "_param_watch": 110, "soon": [110, 113], "p00042": 110, "dir": 110, "startswith": 110, "__": 110, "temp": 110, "0x7f54a49f8b80": 110, "0x7f54a4f15940": 110, "0x7f54a49f8cc0": 110, "get_value_gener": 110, "force_new_dynamic_valu": 110, "reject": [110, 112, 113], "defend": 110, "stuck": 110, "throughout": [110, 113], "_validate_valu": 110, "isinst": 110, "closest": 110, "exclud": 110, "aspect": 110, "crib": 110, "discov": 111, "imper": 111, "primit": 111, "familiar": 111, "spreadsheet": 111, "excel": 111, "formula": 111, "recomput": 111, "bind": 111, "react": 111, "proxi": 111, "dive": 111, "scene": 111, "flow": [111, 113], "dataset": 111, "penguin": 111, "v1": 111, "read_csv": 111, "head": 111, "speci": 111, "island": 111, "bill_length_mm": 111, "bill_depth_mm": 111, "flipper_length_mm": 111, "body_mass_g": 111, "sex": 111, "year": 111, "adeli": 111, "torgersen": 111, "181": 111, "3750": 111, "male": 111, "2007": 111, "17": 111, "186": 111, "3800": 111, "femal": 111, "nrow": 111, "40": 111, "195": 111, "3250": 111, "36": 111, "193": 111, "3450": 111, "190": 111, "3650": 111, "3625": 111, "4675": 111, "34": 111, "3475": 111, "4250": 111, "noth": 111, "set_input": 111, "whoa": 111, "seen": 111, "replai": 111, "complic": [111, 112], "white": 111, "background": 111, "darkblu": 111, "highlight_max": 111, "prop": 111, "dtype": [111, 112], "full_lik": 111, "nanmax": 111, "styled_df": 111, "axi": 111, "700000": 111, "400000": 111, "300000": 111, "600000": 111, "900000": 111, "800000": 111, "200000": 111, "gapmind": 111, "imagin": 111, "ok": 111, "compon": [111, 113], "themselv": [111, 112], "reactive_add": 111, "functool": 111, "add_b": 111, "warg": 111, "wkwarg": 111, "won": [111, 112, 113], "arbitrarili": 111, "almost": 111, "expr": 111, "string_templ": 111, "hello": 111, "fill": 111, "world": 111, "str_expr": 111, "extent": 111, "elif": 111, "ternari": 111, "alongsid": 111, "cast": 111, "absenc": 111, "click": 111, "expensive_funct": 111, "expensive_expr": 111, "bulk": 111, "suffici": 111, "gate": 111, "gated_expr": 111, "paradigm": 111, "value_a": 111, "some_condit": 111, "value_b": 111, "rewrit": 111, "ternary_expr": 111, "constitut": 112, "transmit": 112, "sent": 112, "disk": 112, "human": 112, "portabl": 112, "probabl": 112, "exchang": 112, "send": 112, "network": 112, "nativ": 112, "unpickl": 112, "bytecod": 112, "tree": 112, "inher": 112, "pkl": 112, "snapshot": 112, "checkpoint": 112, "softwar": 112, "archiv": 112, "tradeoff": 112, "default_label_formatt": 112, "timestamp": 112, "a00003": 112, "default_label_formatter00002": 112, "replace_underscor": 112, "1695671713": 112, "950791": 112, "wb": 112, "del": 112, "reload": 112, "rb": 112, "attributeerror": 112, "succeed": 112, "inlin": 112, "pai": 112, "technic": 112, "proper": 112, "smoothli": 112, "parameterizedfunct": [112, 114], "sett": 112, "extract": 112, "fom": 112, "yourclass": 112, "translat": 112, "top": 112, "identifi": 112, "wire": 112, "app": 112, "remot": 112, "propos": 112, "520": 112, "simple_list": 112, "baz": 112, "29": 112, "tmp": 112, "ipykernel_3102": 112, "1070590161": 112, "paramdeprecationwarn": 112, "55": 112, "193836": 112, "p00004": 112, "25t19": 112, "came": 112, "p2": 112, "unpack": 112, "dj": 112, "recogn": 112, "encod": 112, "knew": 112, "perhap": 112, "altogeth": 112, "anyof": 112, "exclusivemaximum": 112, "minitem": 112, "maxitem": 112, "additionalitem": 112, "therein": 112, "jsonschema": 112, "full_schema": 112, "astr": 112, "validationerror": 112, "serializ": 112, "full2": 112, "unknown": 112, "moment": 112, "recreat": 112, "flexibli": 112, "indirect": 112, "q00048": 112, "parameterized00051": 112, "p00049": 112, "consider": 112, "close": [112, 113], "record": 112, "script_repr_suppress_default": 112, "unchang": 112, "Such": 112, "unrepresent": 112, "script_repr_reg": 112, "simultan": 113, "ordinaryclass": 113, "paramclass": 113, "fewer": 113, "ordinaryclass2": 113, "catch": 113, "o4": 113, "mysteri": 113, "concaten": 113, "ordinaryclass3": 113, "o5": 113, "wors": 113, "late": 113, "gotten": 113, "getter": 113, "setter": 113, "ordinaryclass4": 113, "__a": 113, "__b": 113, "__titl": 113, "overlook": 113, "mistak": 113, "extrem": 113, "past": 113, "exercis": 113, "repetit": 113, "esoter": 113, "techniqu": 113, "reader": 113, "quick": 113, "skim": 113, "reveal": 113, "stand": 113, "discern": 113, "increas": 113, "assumpt": 113, "linear": 113, "ream": 113, "sidetrack": 113, "forget": 113, "somedai": 113, "crucial": 113, "piec": 113, "edg": 113, "disallow": 113, "correctli": 113, "advertis": 113, "bulletproof": 113, "mistaken": 113, "malici": 113, "elimin": 114, "unsaf": 114}, "objects": {"": [[6, 0, 0, "-", "numbergen"]], "numbergen": [[6, 1, 1, "", "BinaryOperator"], [6, 1, 1, "", "BoundedNumber"], [6, 1, 1, "", "BoxCar"], [6, 1, 1, "", "Choice"], [6, 1, 1, "", "ExponentialDecay"], [6, 1, 1, "", "NormalRandom"], [6, 1, 1, "", "NumberGenerator"], [6, 1, 1, "", "RandomDistribution"], [6, 1, 1, "", "ScaledTime"], [6, 1, 1, "", "SquareWave"], [6, 1, 1, "", "TimeSampledFn"], [6, 1, 1, "", "UnaryOperator"], [6, 1, 1, "", "UniformRandom"], [6, 1, 1, "", "UniformRandomInt"], [6, 1, 1, "", "UniformRandomOffset"], [6, 1, 1, "", "VonMisesRandom"]], "param": [[7, 1, 1, "", "Action"], [8, 1, 1, "", "Array"], [9, 1, 1, "", "Boolean"], [10, 1, 1, "", "Bytes"], [11, 1, 1, "", "CalendarDateRange"], [12, 1, 1, "", "Callable"], [13, 1, 1, "", "ClassSelector"], [14, 1, 1, "", "Color"], [15, 1, 1, "", "Composite"], [16, 1, 1, "", "DataFrame"], [17, 1, 1, "", "DateRange"], [18, 1, 1, "", "Dict"], [19, 1, 1, "", "Dynamic"], [20, 1, 1, "", "Event"], [21, 1, 1, "", "FileSelector"], [22, 1, 1, "", "Filename"], [23, 1, 1, "", "Foldername"], [24, 1, 1, "", "HookList"], [25, 1, 1, "", "Integer"], [26, 1, 1, "", "List"], [27, 1, 1, "", "ListSelector"], [28, 1, 1, "", "Magnitude"], [29, 1, 1, "", "MultiFileSelector"], [30, 1, 1, "", "Number"], [31, 1, 1, "", "NumericTuple"], [32, 1, 1, "", "ParamOverrides"], [33, 1, 1, "", "Parameter"], [34, 1, 1, "", "Parameterized"], [35, 1, 1, "", "ParameterizedFunction"], [36, 1, 1, "", "Path"], [37, 1, 1, "", "Range"], [38, 1, 1, "", "Selector"], [39, 1, 1, "", "Series"], [40, 1, 1, "", "String"], [41, 1, 1, "", "Tuple"], [42, 1, 1, "", "XYCoordinates"], [43, 3, 1, "", "batch_watch"], [44, 3, 1, "", "concrete_descendents"], [45, 3, 1, "", "depends"], [46, 3, 1, "", "discard_events"], [47, 3, 1, "", "edit_constant"], [48, 3, 1, "", "get_soft_bounds"], [49, 3, 1, "", "guess_bounds"], [50, 3, 1, "", "guess_param_types"], [51, 3, 1, "", "output"], [52, 3, 1, "", "param_union"], [92, 3, 1, "", "script_repr"], [100, 0, 0, "-", "serializer"]], "param.Action": [[7, 2, 1, "", "__init__"]], "param.Array": [[8, 2, 1, "", "__init__"]], "param.Boolean": [[9, 2, 1, "", "__init__"]], "param.Bytes": [[10, 2, 1, "", "__init__"]], "param.CalendarDateRange": [[11, 2, 1, "", "__init__"]], "param.Callable": [[12, 2, 1, "", "__init__"]], "param.ClassSelector": [[13, 2, 1, "", "__init__"]], "param.Color": [[14, 2, 1, "", "__init__"]], "param.Composite": [[15, 2, 1, "", "__init__"]], "param.DataFrame": [[16, 2, 1, "", "__init__"]], "param.DateRange": [[17, 2, 1, "", "__init__"]], "param.Dict": [[18, 2, 1, "", "__init__"]], "param.Dynamic": [[19, 2, 1, "", "__init__"]], "param.Event": [[20, 2, 1, "", "__init__"]], "param.FileSelector": [[21, 2, 1, "", "__init__"]], "param.Filename": [[22, 2, 1, "", "__init__"]], "param.Foldername": [[23, 2, 1, "", "__init__"]], "param.HookList": [[24, 2, 1, "", "__init__"]], "param.Integer": [[25, 2, 1, "", "__init__"]], "param.List": [[26, 2, 1, "", "__init__"]], "param.ListSelector": [[27, 2, 1, "", "__init__"]], "param.Magnitude": [[28, 2, 1, "", "__init__"]], "param.MultiFileSelector": [[29, 2, 1, "", "__init__"]], "param.Number": [[30, 2, 1, "", "__init__"]], "param.NumericTuple": [[31, 2, 1, "", "__init__"]], "param.ParamOverrides": [[32, 2, 1, "", "__init__"]], "param.Parameter": [[33, 2, 1, "", "__init__"]], "param.Parameterized": [[34, 2, 1, "", "__init__"]], "param.ParameterizedFunction": [[35, 2, 1, "", "__init__"]], "param.Path": [[36, 2, 1, "", "__init__"]], "param.Range": [[37, 2, 1, "", "__init__"]], "param.Selector": [[38, 2, 1, "", "__init__"]], "param.Series": [[39, 2, 1, "", "__init__"]], "param.String": [[40, 2, 1, "", "__init__"]], "param.Tuple": [[41, 2, 1, "", "__init__"]], "param.XYCoordinates": [[42, 2, 1, "", "__init__"]], "param.parameterized": [[53, 1, 1, "", "Event"], [88, 1, 1, "", "Watcher"], [89, 3, 1, "", "batch_call_watchers"], [90, 3, 1, "", "get_logger"], [91, 3, 1, "", "logging_level"]], "param.parameterized.Event": [[53, 2, 1, "", "__init__"]], "param.parameterized.Parameters": [[54, 2, 1, "", "add_parameter"], [55, 2, 1, "", "debug"], [56, 2, 1, "", "defaults"], [57, 2, 1, "", "deserialize_parameters"], [58, 2, 1, "", "deserialize_value"], [59, 2, 1, "", "force_new_dynamic_value"], [60, 2, 1, "", "get_param_values"], [61, 2, 1, "", "get_value_generator"], [62, 2, 1, "", "inspect_value"], [63, 2, 1, "", "log"], [64, 2, 1, "", "message"], [65, 2, 1, "", "method_dependencies"], [66, 2, 1, "", "objects"], [67, 2, 1, "", "outputs"], [68, 2, 1, "", "params"], [69, 2, 1, "", "params_depended_on"], [70, 2, 1, "", "pprint"], [71, 2, 1, "", "print_param_defaults"], [72, 2, 1, "", "print_param_values"], [73, 2, 1, "", "schema"], [74, 2, 1, "", "serialize_parameters"], [75, 2, 1, "", "serialize_value"], [76, 2, 1, "", "set_default"], [77, 2, 1, "", "set_dynamic_time_fn"], [78, 2, 1, "", "set_param"], [79, 2, 1, "", "trigger"], [80, 2, 1, "", "unwatch"], [81, 2, 1, "", "update"], [82, 2, 1, "", "values"], [83, 2, 1, "", "verbose"], [84, 2, 1, "", "warning"], [85, 2, 1, "", "watch"], [86, 2, 1, "", "watch_values"], [87, 4, 1, "", "watchers"]], "param.parameterized.Watcher": [[88, 2, 1, "", "__init__"]], "param.serializer": [[100, 3, 1, "", "JSONNullable"], [100, 1, 1, "", "JSONSerialization"], [100, 1, 1, "", "Serialization"], [100, 6, 1, "", "UnsafeserializableException"], [100, 6, 1, "", "UnserializableException"]], "param.serializer.JSONSerialization": [[100, 2, 1, "", "array_schema"], [100, 2, 1, "", "calendardate_schema"], [100, 2, 1, "", "class__schema"], [100, 2, 1, "", "classselector_schema"], [100, 2, 1, "", "dataframe_schema"], [100, 2, 1, "", "date_schema"], [100, 2, 1, "", "declare_numeric_bounds"], [100, 2, 1, "", "deserialize_parameter_value"], [100, 2, 1, "", "deserialize_parameters"], [100, 2, 1, "", "dict_schema"], [100, 2, 1, "", "dumps"], [100, 2, 1, "", "integer_schema"], [100, 5, 1, "", "json_schema_literal_types"], [100, 2, 1, "", "list_schema"], [100, 2, 1, "", "listselector_schema"], [100, 2, 1, "", "loads"], [100, 2, 1, "", "number_schema"], [100, 2, 1, "", "numerictuple_schema"], [100, 2, 1, "", "objectselector_schema"], [100, 2, 1, "", "param_schema"], [100, 2, 1, "", "range_schema"], [100, 2, 1, "", "schema"], [100, 2, 1, "", "selector_schema"], [100, 2, 1, "", "serialize_parameter_value"], [100, 2, 1, "", "serialize_parameters"], [100, 2, 1, "", "tuple_schema"], [100, 5, 1, "", "unserializable_parameter_types"], [100, 2, 1, "", "xycoordinates_schema"]], "param.serializer.Serialization": [[100, 2, 1, "", "deserialize_parameter_value"], [100, 2, 1, "", "deserialize_parameters"], [100, 2, 1, "", "schema"], [100, 2, 1, "", "serialize_parameter_value"], [100, 2, 1, "", "serialize_parameters"]]}, "objtypes": {"0": "py:module", "1": "py:class", "2": "py:method", "3": "py:function", "4": "py:property", "5": "py:attribute", "6": "py:exception"}, "objnames": {"0": ["py", "module", "Python module"], "1": ["py", "class", "Python class"], "2": ["py", "method", "Python method"], "3": ["py", "function", "Python function"], "4": ["py", "property", "Python property"], "5": ["py", "attribute", "Python attribute"], "6": ["py", "exception", "Python exception"]}, "titleterms": {"about": 0, "comparison": 1, "other": [1, 105, 110], "approach": 1, "breviti": 1, "code": [1, 3, 103], "runtim": 1, "check": 1, "gener": [1, 104], "eas": 1, "integr": 1, "your": [1, 103], "project": 1, "gui": [1, 3], "toolkit": 1, "dynam": [1, 19, 104], "valu": [1, 82, 104, 110, 111], "develop": 2, "guid": [2, 114], "setup": 2, "test": 2, "document": 2, "build": [2, 3], "get": [3, 111], "start": [3, 111], "instal": 3, "us": [3, 103, 104, 111, 112], "param": [3, 4, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 95, 103, 104, 105, 108], "simpl": 3, "robust": 3, "configur": 3, "explor": 3, "paramet": [3, 33, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 93, 96, 99, 103, 104, 108, 110, 111], "space": 3, "learn": 3, "more": 3, "welcom": 4, "api": [5, 6, 93], "refer": [5, 6, 93], "numbergen": [6, 104], "action": 7, "arrai": 8, "boolean": [9, 108], "byte": 10, "calendardaterang": 11, "callabl": 12, "classselector": [13, 108], "color": [14, 108], "composit": 15, "datafram": 16, "daterang": 17, "dict": 18, "event": [20, 53, 103], "fileselector": 21, "filenam": 22, "foldernam": 23, "hooklist": 24, "integ": 25, "list": [26, 108], "listselector": 27, "magnitud": 28, "multifileselector": 29, "number": [30, 104, 108], "numerictupl": 31, "paramoverrid": 32, "parameter": [34, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 93, 97, 98, 110, 112], "parameterizedfunct": [35, 109], "path": [36, 108], "rang": 37, "selector": [38, 108], "seri": 39, "string": [40, 108], "tupl": [41, 108], "xycoordin": 42, "batch_watch": 43, "concrete_descend": 44, "depend": [45, 103], "discard_ev": [46, 103], "edit_const": 47, "get_soft_bound": 48, "guess_bound": 49, "guess_param_typ": 50, "output": [51, 67, 107], "param_union": 52, "add_paramet": 54, "debug": 55, "default": 56, "deserialize_paramet": 57, "deserialize_valu": 58, "force_new_dynamic_valu": 59, "get_param_valu": 60, "get_value_gener": 61, "inspect_valu": 62, "log": [63, 93, 94, 106], "messag": [64, 106], "method_depend": 65, "object": [66, 93, 98, 103, 104, 110, 111, 112], "params_depended_on": 69, "pprint": 70, "print_param_default": 71, "print_param_valu": 72, "schema": [73, 112], "serialize_paramet": 74, "serialize_valu": 75, "set_default": 76, "set_dynamic_time_fn": 77, "set_param": 78, "trigger": [79, 103], "unwatch": 80, "updat": 81, "verbos": 83, "warn": [84, 106], "watch": [85, 103], "watch_valu": 86, "watcher": [87, 88, 103], "batch_call_watch": [89, 103], "get_logg": 90, "logging_level": 91, "script_repr": [92, 112], "helper": [93, 96, 97], "namespac": [93, 95, 110], "serial": [93, 100, 112], "releas": 101, "version": 101, "1": 101, "13": 101, "0": 101, "12": 101, "3": 101, "2": 101, "11": 101, "10": 101, "9": 101, "8": 101, "7": 101, "6": 101, "5": 101, "4": 101, "2016": 101, "07": 101, "2015": 101, "04": 101, "03": 101, "2014": 101, "06": 101, "05": 101, "2012": 101, "pre": 101, "2003": 101, "roadmap": 102, "spec": 103, "fals": 103, "function": [103, 111], "async": 103, "executor": 103, "appli": 103, "techniqu": 103, "own": 103, "global": 104, "time": 104, "variabl": 104, "timedepend": 104, "timeawar": 104, "random": 104, "oper": 104, "how": 105, "work": 105, "descriptor": 105, "slot": 105, "metaclass": 105, "custom": 105, "attribut": 105, "access": 105, "note": 105, "write": 106, "control": 106, "level": 106, "format": 106, "count": 106, "type": [108, 110], "classlist": 108, "descend": 108, "invoc": 108, "instanc": [109, 110], "metadata": 110, "inherit": 110, "instanti": 110, "share": 110, "displai": 110, "method": [110, 111], "special": [110, 111], "reactiv": 111, "express": 111, "resolv": 111, "liter": 111, "input": 111, "set": 111, "limit": [111, 112], "rx": 111, "bool": 111, "in_": 111, "arg": 111, "is_": 111, "is_not": 111, "len": 111, "pipe": 111, "func": 111, "kwarg": 111, "when": 111, "condit": 111, "where": 111, "x": 111, "y": 111, "persist": 112, "pickl": 112, "workaround": 112, "json": 112, "simplifi": 113, "codebas": 113, "program": 113, "contract": 113, "user": 114}, "envversion": {"sphinx.domains.c": 2, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 8, "sphinx.domains.index": 1, "sphinx.domains.javascript": 2, "sphinx.domains.math": 2, "sphinx.domains.python": 3, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx.ext.intersphinx": 1, "sphinx.ext.viewcode": 1, "sphinx": 57}, "alltitles": {"About": [[0, "about"]], "Comparison to other approaches": [[1, "comparison-to-other-approaches"]], "Brevity of code": [[1, "brevity-of-code"]], "Runtime checking": [[1, "runtime-checking"]], "Generality and ease of integration with your project": [[1, "generality-and-ease-of-integration-with-your-project"]], "GUI toolkits": [[1, "gui-toolkits"]], "Dynamic values": [[1, "dynamic-values"]], "Developer guide": [[2, "developer-guide"]], "Setup": [[2, "setup"]], "Testing": [[2, "testing"]], "Documentation building": [[2, "documentation-building"]], "Getting Started": [[3, "getting-started"]], "Installation": [[3, "installation"]], "Using Param to get simple, robust code": [[3, "using-param-to-get-simple-robust-code"]], "Using Param for configuration": [[3, "using-param-for-configuration"]], "Using Param to explore parameter spaces": [[3, "using-param-to-explore-parameter-spaces"]], "Using Param to build GUIs": [[3, "using-param-to-build-guis"]], "Learning more": [[3, "learning-more"]], "Welcome to Param!": [[4, "welcome-to-param"]], "API reference": [[5, "api-reference"]], "Numbergen API reference": [[6, "module-numbergen"]], "param.Action": [[7, "param-action"]], "param.Array": [[8, "param-array"]], "param.Boolean": [[9, "param-boolean"]], "param.Bytes": [[10, "param-bytes"]], "param.CalendarDateRange": [[11, "param-calendardaterange"]], "param.Callable": [[12, "param-callable"]], "param.ClassSelector": [[13, "param-classselector"]], "param.Color": [[14, "param-color"]], "param.Composite": [[15, "param-composite"]], "param.DataFrame": [[16, "param-dataframe"]], "param.DateRange": [[17, "param-daterange"]], "param.Dict": [[18, "param-dict"]], "param.Dynamic": [[19, "param-dynamic"], [104, "param-dynamic"]], "param.Event": [[20, "param-event"]], "param.FileSelector": [[21, "param-fileselector"]], "param.Filename": [[22, "param-filename"]], "param.Foldername": [[23, "param-foldername"]], "param.HookList": [[24, "param-hooklist"]], "param.Integer": [[25, "param-integer"]], "param.List": [[26, "param-list"]], "param.ListSelector": [[27, "param-listselector"]], "param.Magnitude": [[28, "param-magnitude"]], "param.MultiFileSelector": [[29, "param-multifileselector"]], "param.Number": [[30, "param-number"]], "param.NumericTuple": [[31, "param-numerictuple"]], "param.ParamOverrides": [[32, "param-paramoverrides"]], "param.Parameter": [[33, "param-parameter"]], "param.Parameterized": [[34, "param-parameterized"]], "param.ParameterizedFunction": [[35, "param-parameterizedfunction"]], "param.Path": [[36, "param-path"]], "param.Range": [[37, "param-range"]], "param.Selector": [[38, "param-selector"]], "param.Series": [[39, "param-series"]], "param.String": [[40, "param-string"]], "param.Tuple": [[41, "param-tuple"]], "param.XYCoordinates": [[42, "param-xycoordinates"]], "param.batch_watch": [[43, "param-batch-watch"]], "param.concrete_descendents": [[44, "param-concrete-descendents"]], "param.depends": [[45, "param-depends"]], "param.discard_events": [[46, "param-discard-events"]], "param.edit_constant": [[47, "param-edit-constant"]], "param.get_soft_bounds": [[48, "param-get-soft-bounds"]], "param.guess_bounds": [[49, "param-guess-bounds"]], "param.guess_param_types": [[50, "param-guess-param-types"]], "param.output": [[51, "param-output"]], "param.param_union": [[52, "param-param-union"]], "param.parameterized.Event": [[53, "param-parameterized-event"]], "param.parameterized.Parameters.add_parameter": [[54, "param-parameterized-parameters-add-parameter"]], "param.parameterized.Parameters.debug": [[55, "param-parameterized-parameters-debug"]], "param.parameterized.Parameters.defaults": [[56, "param-parameterized-parameters-defaults"]], "param.parameterized.Parameters.deserialize_parameters": [[57, "param-parameterized-parameters-deserialize-parameters"]], "param.parameterized.Parameters.deserialize_value": [[58, "param-parameterized-parameters-deserialize-value"]], "param.parameterized.Parameters.force_new_dynamic_value": [[59, "param-parameterized-parameters-force-new-dynamic-value"]], "param.parameterized.Parameters.get_param_values": [[60, "param-parameterized-parameters-get-param-values"]], "param.parameterized.Parameters.get_value_generator": [[61, "param-parameterized-parameters-get-value-generator"]], "param.parameterized.Parameters.inspect_value": [[62, "param-parameterized-parameters-inspect-value"]], "param.parameterized.Parameters.log": [[63, "param-parameterized-parameters-log"]], "param.parameterized.Parameters.message": [[64, "param-parameterized-parameters-message"]], "param.parameterized.Parameters.method_dependencies": [[65, "param-parameterized-parameters-method-dependencies"]], "param.parameterized.Parameters.objects": [[66, "param-parameterized-parameters-objects"]], "param.parameterized.Parameters.outputs": [[67, "param-parameterized-parameters-outputs"]], "param.parameterized.Parameters.params": [[68, "param-parameterized-parameters-params"]], "param.parameterized.Parameters.params_depended_on": [[69, "param-parameterized-parameters-params-depended-on"]], "param.parameterized.Parameters.pprint": [[70, "param-parameterized-parameters-pprint"]], "param.parameterized.Parameters.print_param_defaults": [[71, "param-parameterized-parameters-print-param-defaults"]], "param.parameterized.Parameters.print_param_values": [[72, "param-parameterized-parameters-print-param-values"]], "param.parameterized.Parameters.schema": [[73, "param-parameterized-parameters-schema"]], "param.parameterized.Parameters.serialize_parameters": [[74, "param-parameterized-parameters-serialize-parameters"]], "param.parameterized.Parameters.serialize_value": [[75, "param-parameterized-parameters-serialize-value"]], "param.parameterized.Parameters.set_default": [[76, "param-parameterized-parameters-set-default"]], "param.parameterized.Parameters.set_dynamic_time_fn": [[77, "param-parameterized-parameters-set-dynamic-time-fn"]], "param.parameterized.Parameters.set_param": [[78, "param-parameterized-parameters-set-param"]], "param.parameterized.Parameters.trigger": [[79, "param-parameterized-parameters-trigger"]], "param.parameterized.Parameters.unwatch": [[80, "param-parameterized-parameters-unwatch"]], "param.parameterized.Parameters.update": [[81, "param-parameterized-parameters-update"]], "param.parameterized.Parameters.values": [[82, "param-parameterized-parameters-values"]], "param.parameterized.Parameters.verbose": [[83, "param-parameterized-parameters-verbose"]], "param.parameterized.Parameters.warning": [[84, "param-parameterized-parameters-warning"]], "param.parameterized.Parameters.watch": [[85, "param-parameterized-parameters-watch"]], "param.parameterized.Parameters.watch_values": [[86, "param-parameterized-parameters-watch-values"]], "param.parameterized.Parameters.watchers": [[87, "param-parameterized-parameters-watchers"]], "param.parameterized.Watcher": [[88, "param-parameterized-watcher"]], "param.parameterized.batch_call_watchers": [[89, "param-parameterized-batch-call-watchers"]], "param.parameterized.get_logger": [[90, "param-parameterized-get-logger"]], "param.parameterized.logging_level": [[91, "param-parameterized-logging-level"]], "param.script_repr": [[92, "param-script-repr"]], "Param API reference": [[93, "param-api-reference"]], "Parameterized objects": [[93, "parameterized-objects"], [98, "parameterized-objects"]], "Parameterized helpers": [[93, "parameterized-helpers"], [97, "parameterized-helpers"]], "Parameters": [[93, "parameters"], [99, "parameters"]], "Parameter helpers": [[93, "parameter-helpers"], [96, "parameter-helpers"]], ".param namespace": [[93, "param-namespace"], [95, "param-namespace"]], "Logging": [[93, "logging"], [94, "logging"]], "Serialization": [[93, "module-param.serializer"], [100, "module-param.serializer"]], "Releases": [[101, "releases"]], "Version 1.13.0": [[101, "version-1-13-0"]], "Version 1.12.3": [[101, "version-1-12-3"]], "Version 1.12.2": [[101, "version-1-12-2"]], "Version 1.12.1": [[101, "version-1-12-1"]], "Version 1.12.0": [[101, "version-1-12-0"]], "Version 1.11.1": [[101, "version-1-11-1"]], "Version 1.10.1": [[101, "version-1-10-1"]], "Version 1.10.0": [[101, "version-1-10-0"]], "Version 1.9.3": [[101, "version-1-9-3"]], "Version 1.9.2": [[101, "version-1-9-2"]], "Version 1.9.1": [[101, "version-1-9-1"]], "Version 1.9.0": [[101, "version-1-9-0"]], "Version 1.8.2": [[101, "version-1-8-2"]], "Version 1.8.1": [[101, "version-1-8-1"]], "Version 1.8.0": [[101, "version-1-8-0"]], "Version 1.7.0": [[101, "version-1-7-0"]], "Version 1.6.1": [[101, "version-1-6-1"]], "Version 1.6.0": [[101, "version-1-6-0"]], "Version 1.5.1": [[101, "version-1-5-1"]], "Version 1.5.0": [[101, "version-1-5-0"]], "Version 1.4.2": [[101, "version-1-4-2"]], "Version 1.4.1": [[101, "version-1-4-1"]], "Version 1.4.0 (2016/07)": [[101, "version-1-4-0-2016-07"]], "Version 1.3.2 (2015/04)": [[101, "version-1-3-2-2015-04"]], "Version 1.3.1 (2015/03)": [[101, "version-1-3-1-2015-03"]], "Version 1.3.0 (2015/03)": [[101, "version-1-3-0-2015-03"]], "Version 1.2.1 (2014/06)": [[101, "version-1-2-1-2014-06"]], "Version 1.2.0 (2014/06)": [[101, "version-1-2-0-2014-06"]], "Version 1.1.0 (2014/05)": [[101, "version-1-1-0-2014-05"]], "Version 1.0.0 (2012/07)": [[101, "version-1-0-0-2012-07"]], "Pre-1.0 (2003)": [[101, "pre-1-0-2003"]], "Roadmap": [[102, "roadmap"]], "Dependencies and Watchers": [[103, "dependencies-and-watchers"]], "Dependencies": [[103, "dependencies"]], "Dependency specs": [[103, "dependency-specs"]], "watch=False dependencies": [[103, "watch-false-dependencies"]], "@param.depends with function objects": [[103, "param-depends-with-function-objects"]], "Watchers": [[103, "watchers"]], "Using dependencies and watchers": [[103, "using-dependencies-and-watchers"]], "batch_call_watchers": [[103, "batch-call-watchers"]], "discard_events": [[103, "discard-events"]], ".param.trigger": [[103, "param-trigger"]], ".param.watchers": [[103, "param-watchers"]], "Event Parameter": [[103, "event-parameter"]], "Async executor": [[103, "async-executor"]], "Applying these techniques to your own code": [[103, "applying-these-techniques-to-your-own-code"]], "Dynamic parameter values": [[104, "dynamic-parameter-values"]], "Using a global time variable": [[104, "using-a-global-time-variable"]], "Numbergen": [[104, "numbergen"]], "TimeDependent number generators": [[104, "timedependent-number-generators"]], "TimeAware random number generators": [[104, "timeaware-random-number-generators"]], "Operations on number generators": [[104, "operations-on-number-generators"]], "Using numbergen objects for parameter values": [[104, "using-numbergen-objects-for-parameter-values"]], "How Param Works": [[105, "how-param-works"]], "Descriptors": [[105, "descriptors"]], "Slots": [[105, "slots"]], "Metaclasses": [[105, "metaclasses"]], "Custom attribute access": [[105, "custom-attribute-access"]], "Other notes": [[105, "other-notes"]], "Logging and Warnings": [[106, "logging-and-warnings"]], "Writing log messages": [[106, "writing-log-messages"]], "Controlling the logging level": [[106, "controlling-the-logging-level"]], "Controlling the formatting of log messages": [[106, "controlling-the-formatting-of-log-messages"]], "Counting warnings": [[106, "counting-warnings"]], "Outputs": [[107, "outputs"]], "Parameter types": [[108, "parameter-types"]], "Strings": [[108, "strings"]], "Colors": [[108, "colors"]], "Booleans": [[108, "booleans"]], "Numbers": [[108, "numbers"]], "Tuples": [[108, "tuples"]], "Lists": [[108, "lists"]], "Paths": [[108, "paths"]], "Selectors": [[108, "selectors"]], "ClassSelectors": [[108, "classselectors"]], "classlist and param.descendents": [[108, "classlist-and-param-descendents"]], "Invocations": [[108, "invocations"]], "ParameterizedFunctions": [[109, "parameterizedfunctions"]], ".instance()": [[109, "instance"]], "Parameters and Parameterized objects": [[110, "parameters-and-parameterized-objects"]], "Parameter metadata": [[110, "parameter-metadata"]], "Parameter objects and instances": [[110, "parameter-objects-and-instances"]], "Parameter inheritance": [[110, "parameter-inheritance"]], "Parameter value instantiation": [[110, "parameter-value-instantiation"]], "Parameter object instantiation": [[110, "parameter-object-instantiation"]], "Instantiating with shared parameters": [[110, "instantiating-with-shared-parameters"]], "Displaying Parameterized objects": [[110, "displaying-parameterized-objects"]], "Parameterized namespace": [[110, "parameterized-namespace"]], "Other Parameterized methods": [[110, "other-parameterized-methods"]], "Specialized Parameter types": [[110, "specialized-parameter-types"]], "Reactive Functions & Expressions": [[111, "reactive-functions-expressions"]], "Getting started": [[111, "getting-started"]], "Reactive Functions": [[111, "reactive-functions"]], "Reactive Expressions": [[111, "reactive-expressions"]], "Using Parameters": [[111, "using-parameters"]], "Resolving the expression": [[111, "resolving-the-expression"]], "Using literal objects as inputs": [[111, "using-literal-objects-as-inputs"]], "Setting the input value": [[111, "setting-the-input-value"]], "Functions": [[111, "functions"]], "Special Methods & Limitations": [[111, "special-methods-limitations"]], "Special methods": [[111, "special-methods"]], ".rx.bool()": [[111, "rx-bool"]], ".rx.in_(arg)": [[111, "rx-in-arg"]], ".rx.is_(arg)": [[111, "rx-is-arg"]], ".rx.is_not(arg)": [[111, "rx-is-not-arg"]], ".rx.len()": [[111, "rx-len"]], ".rx.pipe(func, *args, **kwargs)": [[111, "rx-pipe-func-args-kwargs"]], ".rx.when(*conditions)": [[111, "rx-when-conditions"]], ".rx.where(x, y)": [[111, "rx-where-x-y"]], "Serialization and Persistence": [[112, "serialization-and-persistence"]], "Pickling Parameterized objects": [[112, "pickling-parameterized-objects"]], "Using pickling": [[112, "using-pickling"]], "Pickling limitations and workarounds": [[112, "pickling-limitations-and-workarounds"]], "Serializing with JSON": [[112, "serializing-with-json"]], "JSON limitations and workarounds": [[112, "json-limitations-and-workarounds"]], "JSON Schemas": [[112, "json-schemas"]], "script_repr": [[112, "script-repr"]], "script_repr limitations and workarounds": [[112, "script-repr-limitations-and-workarounds"]], "Simplifying Codebases": [[113, "simplifying-codebases"]], "Programming contracts": [[113, "programming-contracts"]], "User Guide": [[114, "user-guide"]]}, "indexentries": {"binaryoperator (class in numbergen)": [[6, "numbergen.BinaryOperator"]], "boundednumber (class in numbergen)": [[6, "numbergen.BoundedNumber"]], "boxcar (class in numbergen)": [[6, "numbergen.BoxCar"]], "choice (class in numbergen)": [[6, "numbergen.Choice"]], "exponentialdecay (class in numbergen)": [[6, "numbergen.ExponentialDecay"]], "normalrandom (class in numbergen)": [[6, "numbergen.NormalRandom"]], "numbergenerator (class in numbergen)": [[6, "numbergen.NumberGenerator"]], "randomdistribution (class in numbergen)": [[6, "numbergen.RandomDistribution"]], "scaledtime (class in numbergen)": [[6, "numbergen.ScaledTime"]], "squarewave (class in numbergen)": [[6, "numbergen.SquareWave"]], "timesampledfn (class in numbergen)": [[6, "numbergen.TimeSampledFn"]], "unaryoperator (class in numbergen)": [[6, "numbergen.UnaryOperator"]], "uniformrandom (class in numbergen)": [[6, "numbergen.UniformRandom"]], "uniformrandomint (class in numbergen)": [[6, "numbergen.UniformRandomInt"]], "uniformrandomoffset (class in numbergen)": [[6, "numbergen.UniformRandomOffset"]], "vonmisesrandom (class in numbergen)": [[6, "numbergen.VonMisesRandom"]], "module": [[6, "module-numbergen"], [93, "module-param.serializer"], [100, "module-param.serializer"]], "numbergen": [[6, "module-numbergen"]], "action (class in param)": [[7, "param.Action"]], "__init__() (param.action method)": [[7, "param.Action.__init__"]], "array (class in param)": [[8, "param.Array"]], "__init__() (param.array method)": [[8, "param.Array.__init__"]], "boolean (class in param)": [[9, "param.Boolean"]], "__init__() (param.boolean method)": [[9, "param.Boolean.__init__"]], "bytes (class in param)": [[10, "param.Bytes"]], "__init__() (param.bytes method)": [[10, "param.Bytes.__init__"]], "calendardaterange (class in param)": [[11, "param.CalendarDateRange"]], "__init__() (param.calendardaterange method)": [[11, "param.CalendarDateRange.__init__"]], "callable (class in param)": [[12, "param.Callable"]], "__init__() (param.callable method)": [[12, "param.Callable.__init__"]], "classselector (class in param)": [[13, "param.ClassSelector"]], "__init__() (param.classselector method)": [[13, "param.ClassSelector.__init__"]], "color (class in param)": [[14, "param.Color"]], "__init__() (param.color method)": [[14, "param.Color.__init__"]], "composite (class in param)": [[15, "param.Composite"]], "__init__() (param.composite method)": [[15, "param.Composite.__init__"]], "dataframe (class in param)": [[16, "param.DataFrame"]], "__init__() (param.dataframe method)": [[16, "param.DataFrame.__init__"]], "daterange (class in param)": [[17, "param.DateRange"]], "__init__() (param.daterange method)": [[17, "param.DateRange.__init__"]], "dict (class in param)": [[18, "param.Dict"]], "__init__() (param.dict method)": [[18, "param.Dict.__init__"]], "dynamic (class in param)": [[19, "param.Dynamic"]], "__init__() (param.dynamic method)": [[19, "param.Dynamic.__init__"]], "event (class in param)": [[20, "param.Event"]], "__init__() (param.event method)": [[20, "param.Event.__init__"]], "fileselector (class in param)": [[21, "param.FileSelector"]], "__init__() (param.fileselector method)": [[21, "param.FileSelector.__init__"]], "filename (class in param)": [[22, "param.Filename"]], "__init__() (param.filename method)": [[22, "param.Filename.__init__"]], "foldername (class in param)": [[23, "param.Foldername"]], "__init__() (param.foldername method)": [[23, "param.Foldername.__init__"]], "hooklist (class in param)": [[24, "param.HookList"]], "__init__() (param.hooklist method)": [[24, "param.HookList.__init__"]], "integer (class in param)": [[25, "param.Integer"]], "__init__() (param.integer method)": [[25, "param.Integer.__init__"]], "list (class in param)": [[26, "param.List"]], "__init__() (param.list method)": [[26, "param.List.__init__"]], "listselector (class in param)": [[27, "param.ListSelector"]], "__init__() (param.listselector method)": [[27, "param.ListSelector.__init__"]], "magnitude (class in param)": [[28, "param.Magnitude"]], "__init__() (param.magnitude method)": [[28, "param.Magnitude.__init__"]], "multifileselector (class in param)": [[29, "param.MultiFileSelector"]], "__init__() (param.multifileselector method)": [[29, "param.MultiFileSelector.__init__"]], "number (class in param)": [[30, "param.Number"]], "__init__() (param.number method)": [[30, "param.Number.__init__"]], "numerictuple (class in param)": [[31, "param.NumericTuple"]], "__init__() (param.numerictuple method)": [[31, "param.NumericTuple.__init__"]], "paramoverrides (class in param)": [[32, "param.ParamOverrides"]], "__init__() (param.paramoverrides method)": [[32, "param.ParamOverrides.__init__"]], "parameter (class in param)": [[33, "param.Parameter"]], "__init__() (param.parameter method)": [[33, "param.Parameter.__init__"]], "parameterized (class in param)": [[34, "param.Parameterized"]], "__init__() (param.parameterized method)": [[34, "param.Parameterized.__init__"]], "parameterizedfunction (class in param)": [[35, "param.ParameterizedFunction"]], "__init__() (param.parameterizedfunction method)": [[35, "param.ParameterizedFunction.__init__"]], "path (class in param)": [[36, "param.Path"]], "__init__() (param.path method)": [[36, "param.Path.__init__"]], "range (class in param)": [[37, "param.Range"]], "__init__() (param.range method)": [[37, "param.Range.__init__"]], "selector (class in param)": [[38, "param.Selector"]], "__init__() (param.selector method)": [[38, "param.Selector.__init__"]], "series (class in param)": [[39, "param.Series"]], "__init__() (param.series method)": [[39, "param.Series.__init__"]], "string (class in param)": [[40, "param.String"]], "__init__() (param.string method)": [[40, "param.String.__init__"]], "tuple (class in param)": [[41, "param.Tuple"]], "__init__() (param.tuple method)": [[41, "param.Tuple.__init__"]], "xycoordinates (class in param)": [[42, "param.XYCoordinates"]], "__init__() (param.xycoordinates method)": [[42, "param.XYCoordinates.__init__"]], "batch_watch() (in module param)": [[43, "param.batch_watch"]], "concrete_descendents() (in module param)": [[44, "param.concrete_descendents"]], "depends() (in module param)": [[45, "param.depends"]], "discard_events() (in module param)": [[46, "param.discard_events"]], "edit_constant() (in module param)": [[47, "param.edit_constant"]], "get_soft_bounds() (in module param)": [[48, "param.get_soft_bounds"]], "guess_bounds() (in module param)": [[49, "param.guess_bounds"]], "guess_param_types() (in module param)": [[50, "param.guess_param_types"]], "output() (in module param)": [[51, "param.output"]], "param_union() (in module param)": [[52, "param.param_union"]], "event (class in param.parameterized)": [[53, "param.parameterized.Event"]], "__init__() (param.parameterized.event method)": [[53, "param.parameterized.Event.__init__"]], "add_parameter() (param.parameterized.parameters method)": [[54, "param.parameterized.Parameters.add_parameter"]], "debug() (param.parameterized.parameters method)": [[55, "param.parameterized.Parameters.debug"]], "defaults() (param.parameterized.parameters method)": [[56, "param.parameterized.Parameters.defaults"]], "deserialize_parameters() (param.parameterized.parameters method)": [[57, "param.parameterized.Parameters.deserialize_parameters"]], "deserialize_value() (param.parameterized.parameters method)": [[58, "param.parameterized.Parameters.deserialize_value"]], "force_new_dynamic_value() (param.parameterized.parameters method)": [[59, "param.parameterized.Parameters.force_new_dynamic_value"]], "get_param_values() (param.parameterized.parameters method)": [[60, "param.parameterized.Parameters.get_param_values"]], "get_value_generator() (param.parameterized.parameters method)": [[61, "param.parameterized.Parameters.get_value_generator"]], "inspect_value() (param.parameterized.parameters method)": [[62, "param.parameterized.Parameters.inspect_value"]], "log() (param.parameterized.parameters method)": [[63, "param.parameterized.Parameters.log"]], "message() (param.parameterized.parameters method)": [[64, "param.parameterized.Parameters.message"]], "method_dependencies() (param.parameterized.parameters method)": [[65, "param.parameterized.Parameters.method_dependencies"]], "objects() (param.parameterized.parameters method)": [[66, "param.parameterized.Parameters.objects"]], "outputs() (param.parameterized.parameters method)": [[67, "param.parameterized.Parameters.outputs"]], "params() (param.parameterized.parameters method)": [[68, "param.parameterized.Parameters.params"]], "params_depended_on() (param.parameterized.parameters method)": [[69, "param.parameterized.Parameters.params_depended_on"]], "pprint() (param.parameterized.parameters method)": [[70, "param.parameterized.Parameters.pprint"]], "print_param_defaults() (param.parameterized.parameters method)": [[71, "param.parameterized.Parameters.print_param_defaults"]], "print_param_values() (param.parameterized.parameters method)": [[72, "param.parameterized.Parameters.print_param_values"]], "schema() (param.parameterized.parameters method)": [[73, "param.parameterized.Parameters.schema"]], "serialize_parameters() (param.parameterized.parameters method)": [[74, "param.parameterized.Parameters.serialize_parameters"]], "serialize_value() (param.parameterized.parameters method)": [[75, "param.parameterized.Parameters.serialize_value"]], "set_default() (param.parameterized.parameters method)": [[76, "param.parameterized.Parameters.set_default"]], "set_dynamic_time_fn() (param.parameterized.parameters method)": [[77, "param.parameterized.Parameters.set_dynamic_time_fn"]], "set_param() (param.parameterized.parameters method)": [[78, "param.parameterized.Parameters.set_param"]], "trigger() (param.parameterized.parameters method)": [[79, "param.parameterized.Parameters.trigger"]], "unwatch() (param.parameterized.parameters method)": [[80, "param.parameterized.Parameters.unwatch"]], "update() (param.parameterized.parameters method)": [[81, "param.parameterized.Parameters.update"]], "values() (param.parameterized.parameters method)": [[82, "param.parameterized.Parameters.values"]], "verbose() (param.parameterized.parameters method)": [[83, "param.parameterized.Parameters.verbose"]], "warning() (param.parameterized.parameters method)": [[84, "param.parameterized.Parameters.warning"]], "watch() (param.parameterized.parameters method)": [[85, "param.parameterized.Parameters.watch"]], "watch_values() (param.parameterized.parameters method)": [[86, "param.parameterized.Parameters.watch_values"]], "watchers (param.parameterized.parameters property)": [[87, "param.parameterized.Parameters.watchers"]], "watcher (class in param.parameterized)": [[88, "param.parameterized.Watcher"]], "__init__() (param.parameterized.watcher method)": [[88, "param.parameterized.Watcher.__init__"]], "batch_call_watchers() (in module param.parameterized)": [[89, "param.parameterized.batch_call_watchers"]], "get_logger() (in module param.parameterized)": [[90, "param.parameterized.get_logger"]], "logging_level() (in module param.parameterized)": [[91, "param.parameterized.logging_level"]], "script_repr() (in module param)": [[92, "param.script_repr"]], "jsonnullable() (in module param.serializer)": [[93, "param.serializer.JSONNullable"], [100, "param.serializer.JSONNullable"]], "jsonserialization (class in param.serializer)": [[93, "param.serializer.JSONSerialization"], [100, "param.serializer.JSONSerialization"]], "serialization (class in param.serializer)": [[93, "param.serializer.Serialization"], [100, "param.serializer.Serialization"]], "unsafeserializableexception": [[93, "param.serializer.UnsafeserializableException"], [100, "param.serializer.UnsafeserializableException"]], "unserializableexception": [[93, "param.serializer.UnserializableException"], [100, "param.serializer.UnserializableException"]], "array_schema() (param.serializer.jsonserialization class method)": [[93, "param.serializer.JSONSerialization.array_schema"], [100, "param.serializer.JSONSerialization.array_schema"]], "calendardate_schema() (param.serializer.jsonserialization class method)": [[93, "param.serializer.JSONSerialization.calendardate_schema"], [100, "param.serializer.JSONSerialization.calendardate_schema"]], "class__schema() (param.serializer.jsonserialization class method)": [[93, "param.serializer.JSONSerialization.class__schema"], [100, "param.serializer.JSONSerialization.class__schema"]], "classselector_schema() (param.serializer.jsonserialization class method)": [[93, "param.serializer.JSONSerialization.classselector_schema"], [100, "param.serializer.JSONSerialization.classselector_schema"]], "dataframe_schema() (param.serializer.jsonserialization class method)": [[93, "param.serializer.JSONSerialization.dataframe_schema"], [100, "param.serializer.JSONSerialization.dataframe_schema"]], "date_schema() (param.serializer.jsonserialization class method)": [[93, "param.serializer.JSONSerialization.date_schema"], [100, "param.serializer.JSONSerialization.date_schema"]], "declare_numeric_bounds() (param.serializer.jsonserialization class method)": [[93, "param.serializer.JSONSerialization.declare_numeric_bounds"], [100, "param.serializer.JSONSerialization.declare_numeric_bounds"]], "deserialize_parameter_value() (param.serializer.jsonserialization class method)": [[93, "param.serializer.JSONSerialization.deserialize_parameter_value"], [100, "param.serializer.JSONSerialization.deserialize_parameter_value"]], "deserialize_parameter_value() (param.serializer.serialization class method)": [[93, "param.serializer.Serialization.deserialize_parameter_value"], [100, "param.serializer.Serialization.deserialize_parameter_value"]], "deserialize_parameters() (param.serializer.jsonserialization class method)": [[93, "param.serializer.JSONSerialization.deserialize_parameters"], [100, "param.serializer.JSONSerialization.deserialize_parameters"]], "deserialize_parameters() (param.serializer.serialization class method)": [[93, "param.serializer.Serialization.deserialize_parameters"], [100, "param.serializer.Serialization.deserialize_parameters"]], "dict_schema() (param.serializer.jsonserialization class method)": [[93, "param.serializer.JSONSerialization.dict_schema"], [100, "param.serializer.JSONSerialization.dict_schema"]], "dumps() (param.serializer.jsonserialization class method)": [[93, "param.serializer.JSONSerialization.dumps"], [100, "param.serializer.JSONSerialization.dumps"]], "integer_schema() (param.serializer.jsonserialization class method)": [[93, "param.serializer.JSONSerialization.integer_schema"], [100, "param.serializer.JSONSerialization.integer_schema"]], "json_schema_literal_types (param.serializer.jsonserialization attribute)": [[93, "param.serializer.JSONSerialization.json_schema_literal_types"], [100, "param.serializer.JSONSerialization.json_schema_literal_types"]], "list_schema() (param.serializer.jsonserialization class method)": [[93, "param.serializer.JSONSerialization.list_schema"], [100, "param.serializer.JSONSerialization.list_schema"]], "listselector_schema() (param.serializer.jsonserialization class method)": [[93, "param.serializer.JSONSerialization.listselector_schema"], [100, "param.serializer.JSONSerialization.listselector_schema"]], "loads() (param.serializer.jsonserialization class method)": [[93, "param.serializer.JSONSerialization.loads"], [100, "param.serializer.JSONSerialization.loads"]], "number_schema() (param.serializer.jsonserialization class method)": [[93, "param.serializer.JSONSerialization.number_schema"], [100, "param.serializer.JSONSerialization.number_schema"]], "numerictuple_schema() (param.serializer.jsonserialization class method)": [[93, "param.serializer.JSONSerialization.numerictuple_schema"], [100, "param.serializer.JSONSerialization.numerictuple_schema"]], "objectselector_schema() (param.serializer.jsonserialization class method)": [[93, "param.serializer.JSONSerialization.objectselector_schema"], [100, "param.serializer.JSONSerialization.objectselector_schema"]], "param.serializer": [[93, "module-param.serializer"], [100, "module-param.serializer"]], "param_schema() (param.serializer.jsonserialization class method)": [[93, "param.serializer.JSONSerialization.param_schema"], [100, "param.serializer.JSONSerialization.param_schema"]], "range_schema() (param.serializer.jsonserialization class method)": [[93, "param.serializer.JSONSerialization.range_schema"], [100, "param.serializer.JSONSerialization.range_schema"]], "schema() (param.serializer.jsonserialization class method)": [[93, "param.serializer.JSONSerialization.schema"], [100, "param.serializer.JSONSerialization.schema"]], "schema() (param.serializer.serialization class method)": [[93, "param.serializer.Serialization.schema"], [100, "param.serializer.Serialization.schema"]], "selector_schema() (param.serializer.jsonserialization class method)": [[93, "param.serializer.JSONSerialization.selector_schema"], [100, "param.serializer.JSONSerialization.selector_schema"]], "serialize_parameter_value() (param.serializer.jsonserialization class method)": [[93, "param.serializer.JSONSerialization.serialize_parameter_value"], [100, "param.serializer.JSONSerialization.serialize_parameter_value"]], "serialize_parameter_value() (param.serializer.serialization class method)": [[93, "param.serializer.Serialization.serialize_parameter_value"], [100, "param.serializer.Serialization.serialize_parameter_value"]], "serialize_parameters() (param.serializer.jsonserialization class method)": [[93, "param.serializer.JSONSerialization.serialize_parameters"], [100, "param.serializer.JSONSerialization.serialize_parameters"]], "serialize_parameters() (param.serializer.serialization class method)": [[93, "param.serializer.Serialization.serialize_parameters"], [100, "param.serializer.Serialization.serialize_parameters"]], "tuple_schema() (param.serializer.jsonserialization class method)": [[93, "param.serializer.JSONSerialization.tuple_schema"], [100, "param.serializer.JSONSerialization.tuple_schema"]], "unserializable_parameter_types (param.serializer.jsonserialization attribute)": [[93, "param.serializer.JSONSerialization.unserializable_parameter_types"], [100, "param.serializer.JSONSerialization.unserializable_parameter_types"]], "xycoordinates_schema() (param.serializer.jsonserialization class method)": [[93, "param.serializer.JSONSerialization.xycoordinates_schema"], [100, "param.serializer.JSONSerialization.xycoordinates_schema"]]}}) \ No newline at end of file diff --git a/user_guide/Dependencies_and_Watchers.html b/user_guide/Dependencies_and_Watchers.html new file mode 100644 index 0000000..d2a5b3e --- /dev/null +++ b/user_guide/Dependencies_and_Watchers.html @@ -0,0 +1,2111 @@ + + + + + + + + + + + + Dependencies and Watchers — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

Dependencies and Watchers#

+

As outlined in the Dynamic Parameters guide, Param can be used in multiple ways, including as a static set of typed attributes, dynamic attributes that are computed when they are read (param.Dynamic parameters, a “pull” or “get” model), and using explicitly expressed chains of actions driven by events at the Parameter level (a “push” or “set” model described in this notebook).

+

Unlike Dynamic Parameters, which calculate values when parameters are accessed, the dependency and watcher interface allows events to be triggered when parameters are set. With this interface, parameters and methods can declare that they should be updated or invoked when a given parameter is modified, spawning a cascading series of events that update settings to be consistent, adapt values as appropriate for a change, or invoke computations such as updating a displayed object when a value is modified. This approach is well suited to a GUI interface, where a user interacts with a single widget at a time but other widgets or displays need to be updated in response. The +Dynamic Parameters approach, in contrast, is well suited when Parameters update either on read or in response to a global clock or counter, such as in a simulation or machine-learning iteration.

+

This user guide is structured as three main sections:

+
    +
  • Dependencies: High-level dependency declaration via the @param.depends() decorator

  • +
  • Watchers: Low-level watching mechanism via .param.watch().

  • +
  • Using dependencies and watchers: Utilities and tools for working with events created using either dependencies or watchers.

  • +
+
+

Dependencies#

+

Param’s depends decorator allows a programmer to express that a given computation “depends” on a certain set of parameters. For instance, if you have parameters whose values are interlinked, it’s easy to express that relationship with depends:

+
+
+
import param
+
+class C(param.Parameterized):
+    _countries = {'Africa': ['Ghana', 'Togo', 'South Africa'],
+                  'Asia'  : ['China', 'Thailand', 'Japan', 'Singapore'],
+                  'Europe': ['Austria', 'Bulgaria', 'Greece', 'Switzerland']}
+    
+    continent = param.Selector(default='Asia', objects=list(_countries.keys()))
+    country = param.Selector(objects=_countries['Asia'])
+    
+    @param.depends('continent', watch=True)
+    def _update_countries(self):
+        countries = self._countries[self.continent]
+        self.param['country'].objects = countries
+        if self.country not in countries:
+            self.country = countries[0]
+
+c = C()
+c.country, c.param.country.objects
+
+
+
+
+
('China', ['China', 'Thailand', 'Japan', 'Singapore'])
+
+
+
+
+
+
+
c.continent='Africa'
+c.country, c.param.country.objects
+
+
+
+
+
('Ghana', ['Ghana', 'Togo', 'South Africa'])
+
+
+
+
+
+
+
c
+
+
+
+
+
C(continent='Africa', country='Ghana', name='C00002')
+
+
+
+
+

As you can see, here Param updates the allowed and current values for country whenever someone changes the continent parameter. This code relies on the dependency mechanism to make sure these parameters are kept appropriately synchronized:

+
    +
  1. First, we set up the default continent but do not declare the objects and default for the country parameter. This is because this parameter is dependent on the continent and therefore it is easy to set up values that are inconsistent and makes it difficult to override the default continent since changes to both parameters need to be coordinated.

  2. +
  3. Next, if someone chooses a different continent, the list of countries allowed needs to be updated, so the method _update_countries() that (a) looks up the countries allowed for the current continent, (b) sets that list as the allowed objects for the country parameter, and (c) selects the first such country as the default country.

  4. +
  5. Finally, we expressed that the _update_countries() method depends on the continent parameter. We specified watch=True to direct Param to invoke this method immediately, whenever the value of continent changes. We’ll see examples of watch=False later. Importantly we also set on_init=True, which means that when instance is created the self._update_countries() method is automatically called setting up the country parameter appropriately. This avoids having to declare a __init__ method to manually call the method ourselves and the potentially brittle process of setting up consistent defaults.

  6. +
+
+

Dependency specs#

+

The example above expressed a dependency of _update_countries on this object’s continent parameter. A wide range of such dependency relationships can be specified:

+
    +
  1. Multiple dependencies: Here we had only one parameter in the dependency list, but you can supply any number of dependencies (@param.depends('continent', 'country', watch=True)).

  2. +
  3. Dependencies on nested parameters: Parameters specified can either be on this class, or on nested Parameterized objects of this class. Parameters on this class are specified as the attribute name as a simple string (like 'continent'). Nested parameters are specified as a dot-separated string (like 'handler.strategy.i', if this object has a parameter handler, whose value is an object strategy, which itself has a parameter i). If you want to depend on some arbitrary parameter elsewhere in Python, just create an instantiate=False (and typically read-only) parameter on this class to hold it, then here you can specify the path to it on this object.

  4. +
  5. Dependencies on metadata: By default, dependencies are tied to a parameter’s current value, but dependencies can also be on any of the declared metadata about the parameter (e.g. a method could depend on country:constant, triggering when someone changes whether that parameter is constant, or on country:objects (triggering when the objects list is replaced (not just changed in place as in appending). The available metadata is listed in the __slots__ attribute of a Parameter object (e.g. +p.param.continent.__slots__).

  6. +
  7. Dependencies on any nested param: If you want to depend on all the parameters of a nested object n, your method can depend on 'n.param' (where parameter n has been set to a Parameterized object).

  8. +
  9. Dependencies on a method name: Often you will want to break up computation into multiple chunks, some of which are useful on their own and some which require other computations to have been done as prerequisites. In this case, your method can declare a dependency on another method (as a string name), which means that it will now watch everything that method watches, and will then get invoked after that method is invoked.

  10. +
+

We can see examples of all these dependency specifications in class D below:

+
+
+
class D(param.Parameterized):
+    x = param.Number(7)
+    s = param.String("never")
+    i = param.Integer(-5)
+    o = param.Selector(objects=['red', 'green', 'blue'])
+    n = param.ClassSelector(default=c, class_=param.Parameterized, instantiate=False)                    
+    
+    @param.depends('x', 's', 'n.country', 's:constant', watch=True)
+    def cb1(self):
+        print(f"cb1 x={self.x} s={self.s} "
+              f"param.s.constant={self.param.s.constant} n.country={self.n.country}")
+
+    @param.depends('n.param', watch=True)
+    def cb2(self):
+        print(f"cb2 n={self.n}")
+
+    @param.depends('x', 'i', watch=True)
+    def cb3(self):
+        print(f"cb3 x={self.x} i={self.i}")
+
+    @param.depends('cb3', watch=True)
+    def cb4(self):
+        print(f"cb4 x={self.x} i={self.i}")
+
+d = D()
+d
+
+
+
+
+
D(i=-5, n=C(continent='Africa', country='Ghana', name='C00002'), name='D00003', o='red', s='never', x=7)
+
+
+
+
+

Here we have created an object d of type D with a unique ID like D00003. d has various parameters, including one nested Parameterized object in its parameter n. In this class, the nested parameter is set to our earlier object c, using instantiate=False to ensure that the value is precisely the same earlier object, not a copy of it. You can verify that it is the same object by comparing e.g. name='C00002' in the repr for the subobject in d to the name in the repr for c in the previous section; both should be e.g. C00002.

+

Dependencies are stored declaratively so that they are accessible for other libraries to inspect and use. E.g. we can now examine the dependencies for the decorated callback method cb1:

+
+
+
dependencies = d.param.method_dependencies('cb1')
+[f"{o.inst.name}.{o.pobj.name}:{o.what}" for o in dependencies]
+
+
+
+
+
['D00003.x:value',
+ 'D00003.s:value',
+ 'D00003.s:constant',
+ 'C00002.country:value']
+
+
+
+
+

Here we can see that method cb1 will be invoked for any value changes in d’s parameters x or s, for any value changes in c’s parameter country, and a change in the constant slot of s. These dependency relationships correspond to the specification @param.depends('x', 's', 'n.country', 's:constant', watch=True) above.

+

Now, if we change x, we can see that Param invokes cb1:

+
+
+
d.x = 5
+
+
+
+
+
cb1 x=5 s=never param.s.constant=False n.country=Ghana
+cb3 x=5 i=-5
+cb4 x=5 i=-5
+
+
+
+
+

cb3 and cb4 are also invoked, because cb3 depends on x as well, plus cb4 depends on cb3, inheriting all of cb3’s dependencies.

+

If we now change c.country, cb1 will be invoked since cb1 depends on n.country, and n is currently set to c:

+
+
+
c.country = 'Togo'
+
+
+
+
+
cb1 x=5 s=never param.s.constant=False n.country=Togo
+cb2 n=<C C00002>
+
+
+
+
+

As you can see, cb2 is also invoked, because cb2 depends on all parameters of the subobject in n.

+

continent is also a parameter on c, so cb2 will also be invoked if you change c.continent. Note that changing c.continent itself invokes c._update_countries(), so in that case cb2 actually gets invoked twice (once for each parameter changed on c), along with cb1 (watching n.country):

+
+
+
c.continent = 'Europe'
+
+
+
+
+
cb1 x=5 s=never param.s.constant=False n.country=Austria
+cb2 n=<C C00002>
+cb2 n=<C C00002>
+
+
+
+
+

Changing metadata works just the same as changing values. Because cb1 depends on the constant slot of s, it is invoked when that slot changes:

+
+
+
d.param.s.constant = True
+
+
+
+
+
cb1 x=5 s=never param.s.constant=True n.country=Austria
+
+
+
+
+

Importantly, if we replace a sub-object on which we have declared dependencies, Param automatically rebinds the dependencies to the new object:

+
+
+
d.n = C()
+
+
+
+
+
cb1 x=5 s=never param.s.constant=True n.country=China
+cb2 n=<C C00004>
+
+
+
+
+

Note that if the values of the dependencies on the old and new object are the same, no event is fired.

+

Additionally the previously bound sub-object is now no longer connected:

+
+
+
c.continent = 'Europe'
+
+
+
+
+
+
+

watch=False dependencies#

+

The previous examples all supplied watch=True, indicating that Param itself should watch for changes in the dependency and invoke that method when a dependent parameter is set. If watch=False (the default), @param.depends declares that such a dependency exists, but does not automatically invoke it. watch=False is useful for setting up code for a separate library like Panel or HoloViews to use, indicating which parameters the external library should watch so that it knows when to invoke the decorated method. Typically, you’ll want to use watch=False when that external library needs to do something with the return value of the method (a functional approach), and use watch=True when the function is side-effecty, i.e. having an effect just from running it, and not normally returning a value.

+

For instance, consider this Param class with methods that return values to display:

+
+
+
class Mul(param.Parameterized):
+    a = param.Number(5,  bounds=(-100, 100))
+    b = param.Number(-2, bounds=(-100, 100))
+
+    @param.depends('a', 'b')
+    def view(self):
+        return str(self.a*self.b)
+
+    def view2(self):
+        return str(self.a*self.b)
+
+prod = Mul(name='Multiplier')
+
+
+
+
+

You could run this code manually:

+
+
+
prod.a = 7
+prod.b = 10
+prod.view()
+
+
+
+
+
'70'
+
+
+
+
+

Or you could pass the parameters and the view method to Panel, and let Panel invoke it as needed by following the dependency chain:

+
+
+
import panel as pn
+pn.extension()
+
+
+
+
+
+
+
+
+
+
+
+
pn.Row(prod.param, prod.view)
+
+
+
+
+
/home/runner/.local/share/hatch/env/virtual/param/vEFSptNL/docs/lib/python3.9/site-packages/panel/viewable.py:298: ParamFutureWarning: Parameter 'object' on <class 'panel.pane.base.PaneBase'> is being given a valid parameter reference <bound method Mul.view of Mul(a=7, b=10, name='Multiplier')> but is implicitly allow_refs=False. In future allow_refs will be enabled by default and the reference <bound method Mul.view of Mul(a=7, b=10, name='Multiplier')> will be resolved to its underlying value 70. Please explicitly set allow_ref on the Parameter definition to declare whether references should be resolved or not.
+  super().__init__(**params)
+
+
+
+
+
+
+
+

Panel creates widgets for the parameters, runs the view method with the default values of those parameters, and displays the result. As long as you have a live Python process running (not just a static HTML export of this page as on param.holoviz.org), Panel will then watch for changes in those parameters due to the widgets and will re-execute the view method to update the output whenever one of those parameters changes. Using the dependency declarations, Panel is able to do all this without ever having to be told separately which parameters there are or what dependency relationships there are.

+

How does that work? A library like Panel can simply ask Param what dependency relationships have been declared for the method passed to it:

+
+
+
[o.name for o in prod.param.method_dependencies('view')]
+
+
+
+
+
['a', 'b']
+
+
+
+
+

Note that in this particular case the depends decorator could have been omitted, because Param conservatively assumes that any method could read the value of any parameter, and thus if it has no other declaration from the user, the dependencies are assumed to include all parameters (including name, even though it is constant):

+
+
+
[o.name for o in prod.param.method_dependencies('view2')]
+
+
+
+
+
['name', 'a', 'b']
+
+
+
+
+

Conversely, if you want to declare that a given method does not depend on any parameters at all, you can use @param.depends().

+

Be sure not to set watch=True for dependencies for any method you pass to an external library like Panel to handle, or else that method will get invoked twice, once by Param itself (discarding the output) and once by the external library (using the output). Typically you will want watch=True for a side-effecty function or method (typically not returning a value), and watch=False (the default) for a function or method with a return value, and you’ll need an external library to do something with that return value.

+
+
+

@param.depends with function objects#

+

The depends decorator can also be used with bare functions, in which case the specification should be an actual Parameter object, not a string. The function will be called with the parameter(s)’s value(s) as positional arguments:

+
+
+
@param.depends(c.param.country, d.param.i, watch=True)
+def g(country, i):
+    print(f"g country={country} i={i}")
+
+c.country = 'Greece'
+
+
+
+
+
g country=Greece i=-5
+
+
+
+
+
+
+
d.i = 6
+
+
+
+
+
cb3 x=5 i=6
+cb4 x=5 i=6
+g country=Greece i=6
+
+
+
+
+

Here you can see that in addition to the classmethods starting with cb previously set up to depend on the country, setting c’s country parameter or d’s i parameter now also invokes function g, passing in the current values of the parameters it depends on whenever the function gets invoked. g can then make a side effect happen such as updating any other data structure it can access that needs to be changed when country or i changes.

+

Using @param.depends(..., watch=False) with a function allows providing bound standalone functions to an external library for display, just as in the .view method above.

+

Of course, you can still invoke g with your own explicit arguments, which does not invoke any watching mechanisms:

+
+
+
g('USA', 7)
+
+
+
+
+
g country=USA i=7
+
+
+
+
+
+
+
+

Watchers#

+

The depends decorator is built on Param’s lower-level .param.watch interface, registering the decorated method or function as a Watcher object associated with those parameter(s). If you’re building or using a complex library like Panel, you can use the low-level Parameter watching interface to set up arbitrary chains of watchers to respond to parameter value or metadata setting:

+
    +
  • obj.param.watch(fn, parameter_names, what='value', onlychanged=True, queued=False, precedence=0):
    Create and register a Watcher that will invoke the given callback fn when the what item (value or one of the Parameter’s slots) is set (or more specifically, changed, if onlychanged=True). If queued=True, delays calling any events triggered during this callback’s execution until all processing of the current events has been completed (breadth-first Event processing rather than the default depth-first processing). The precedence declares a precedence level for the Watcher that determines the priority with which the callback is executed. Lower precedence levels are executed earlier. Negative precedences are reserved for internal Watchers, i.e. those set up by param.depends. The fn will be invoked with one or more Event objects that have been triggered, as positional arguments. Returns a Watcher object, e.g. for use in unwatch.

  • +
  • obj.param.watch_values(fn, parameter_names, what='value', onlychanged=True, queued=False, precedence=0):
    Easier-to-use version of obj.param.watch specific to watching for changes in parameter values. Same as watch, but hard-codes what='value' and invokes the callback fn using keyword arguments param_name=new_value rather than with a positional-argument list of Event objects.

  • +
  • obj.param.unwatch(watcher):
    Remove the given Watcher (typically obtained as the return value from watch or watch_values) from those registered on this obj.

  • +
+

To see how to use watch and watch_values, let’s make a class with parameters a and b and various watchers with corresponding callback methods:

+
+
+
def e(e):
+    return f"(event: {e.name} changed from {e.old} to {e.new})"
+
+class P(param.Parameterized):
+    a = param.Integer(default=0)
+    b = param.Integer(default=0)
+    
+    def __init__(self, **params):
+        super().__init__(**params)
+        self.param.watch(self.run_a1, ['a'], queued=True, precedence=2)
+        self.param.watch(self.run_a2, ['a'], precedence=1)
+        self.param.watch(self.run_b,  ['b'])
+
+    def run_a1(self, event):
+        self.b += 1
+        print('a1', self.a, e(event))
+
+    def run_a2(self, event):
+        print('a2', self.a, e(event))
+
+    def run_b(self, event):
+        print('b', self.b, e(event))
+        
+p = P()
+
+p.a = 1
+
+
+
+
+
a2 1 (event: a changed from 0 to 1)
+a1 1 (event: a changed from 0 to 1)
+b 1 (event: b changed from 0 to 1)
+
+
+
+
+

Here, we have set up three Watchers, each invoking a method on P when either a or b changes. The first Watcher invokes run_a1 when a changes, and in turn run_a1 changes b. Since queued=True for run_a1, run_b is not invoked while run_a1 executes, but only later once both run_a1 and run_a2 have completed (since both Watchers were triggered by the original event p.a=1).

+

Additionally we have set a higher precedence value for run_a1 which results in it being executed after run_a2.

+

Here we’re using data from the Event objects given to each callback to see what’s changed; try help(param.parameterized.Event) for details of what is in these objects (and similarly try the help for Watcher (returned by watch) or PInfo (returned by .param.method_dependencies)).

+
+
+
#help(param.parameterized.Event)
+#help(param.parameterized.Watcher)
+#help(param.parameterized.PInfo)
+
+
+
+
+
+
+

Using dependencies and watchers#

+

Whether you use the watch or the depends approach, Param will store a set of Watcher objects on each Parameterized object that let it manage and process Events. Param provides various context managers, methods, and Parameters that help you work with Watchers and Events:

+
    +
  • batch_call_watchers: context manager accumulating and eliding multiple Events to be applied on exit from the context

  • +
  • discard_events: context manager silently discarding events generated while in the context

  • +
  • .param.trigger: method to force creation of an Event for this Parameter’s Watchers without a corresponding change to the Parameter

  • +
  • .param.watchers: writable property to access the instance watchers

  • +
  • Event Parameter: Special Parameter type providing triggerable transient Events (like a momentary push button)

  • +
  • Async executor: Support for asynchronous processing of Events, e.g. for interfacing to external servers

  • +
+

Each of these will be described in the following sections.

+
+

batch_call_watchers#

+

Context manager that accumulates parameter changes on the supplied object and dispatches them all at once when the context is exited, to allow multiple changes to a given parameter to be accumulated and short-circuited, rather than prompting serial changes from a batch of parameter setting:

+
+
+
with param.parameterized.batch_call_watchers(p):
+    p.a = 2
+    p.a = 3
+    p.a = 1
+    p.a = 5
+
+
+
+
+
a2 5 (event: a changed from 1 to 5)
+a1 5 (event: a changed from 1 to 5)
+b 2 (event: b changed from 1 to 2)
+
+
+
+
+

Here, even though p.a is changed four times, each of the watchers of a is executed only once, with the final value. One of those events then changes b, so b’s watcher is also executed once.

+

If we set b explicitly, b’s watcher will be invoked twice, once for the explicit setting of b, and once because of the code self.b += 1:

+
+
+
with param.parameterized.batch_call_watchers(p):
+    p.a = 2
+    p.b = 8
+    p.a = 3
+    p.a = 1
+    p.a = 5
+
+
+
+
+
b 8 (event: b changed from 2 to 8)
+a2 5 (event: a changed from 1 to 5)
+a1 5 (event: a changed from 1 to 5)
+b 9 (event: b changed from 8 to 9)
+
+
+
+
+

If all you need to do is set a batch of parameters, you can use .update instead of batch_call_watchers, which has the same underlying batching mechanism:

+
+
+
p.param.update(a=9,b=2)
+
+
+
+
+
b 2 (event: b changed from 9 to 2)
+a2 9 (event: a changed from 5 to 9)
+a1 9 (event: a changed from 5 to 9)
+b 3 (event: b changed from 2 to 3)
+
+
+
<param.parameterized._ParametersRestorer at 0x7f471c62ce80>
+
+
+
+
+
+
+

discard_events#

+

Context manager that discards any events within its scope that are triggered on the supplied parameterized object. Useful for making silent changes to dependent parameters, e.g. in a setup phase. If your dependencies are meant to ensure consistency between parameters, be careful that your manual changes in this context don’t put the object into an inconsistent state!

+
+
+
with param.parameterized.discard_events(p):
+    p.a = 2
+    p.b = 9
+
+
+
+
+

(Notice that none of the callbacks is invoked, despite all the Watchers on p.a and p.b.)

+
+
+

.param.trigger#

+

Usually, a Watcher will be invoked only when a parameter is set (and only if it is changed, by default). What if you want to trigger a Watcher in other cases? For instance, if a parameter value is a mutable container like a list and you add or change an item in that container, Param’s set method will never be invoked, because in Python the container itself is not changed when the contents are changed. In such cases, you can trigger a watcher explicitly, using .param.trigger(*param_names). Triggering does not affect parameter values, apart from the special parameters of type Event (see below).

+

For instance, if you set p.b to the value it already has, no callback will normally be invoked:

+
+
+
p.b = p.b
+
+
+
+
+

But if you explicitly trigger parameter b on p, run_b will be invoked, even though the value of b is not changing:

+
+
+
p.param.trigger('b')
+
+
+
+
+
b 9 (event: b changed from 9 to 9)
+
+
+
+
+

If you trigger a, the usual series of chained events will be triggered, including changing b:

+
+
+
p.param.trigger('a')
+
+
+
+
+
a2 2 (event: a changed from 2 to 2)
+a1 2 (event: a changed from 2 to 2)
+b 10 (event: b changed from 9 to 10)
+
+
+
+
+
+
+

.param.watchers#

+

For more advanced purposes it can be useful to inspect all the watchers set up on an instance, in which case you can use inst.param.watchers to obtain a dictionary with the following structure: {parameter_name: {what: [Watcher(), ...], ...}, ...}

+
+
+
p.param.watchers
+
+
+
+
+
{'a': {'value': [Watcher(inst=P(a=2, b=10, name='P00180'), cls=<class '__main__.P'>, fn=<bound method P.run_a1 of P(a=2, b=10, name='P00180')>, mode='args', onlychanged=True, parameter_names=('a',), what='value', queued=True, precedence=2),
+   Watcher(inst=P(a=2, b=10, name='P00180'), cls=<class '__main__.P'>, fn=<bound method P.run_a2 of P(a=2, b=10, name='P00180')>, mode='args', onlychanged=True, parameter_names=('a',), what='value', queued=False, precedence=1)]},
+ 'b': {'value': [Watcher(inst=P(a=2, b=10, name='P00180'), cls=<class '__main__.P'>, fn=<bound method P.run_b of P(a=2, b=10, name='P00180')>, mode='args', onlychanged=True, parameter_names=('b',), what='value', queued=False, precedence=0)]}}
+
+
+
+
+
+
+

Event Parameter#

+

An Event Parameter is a special Parameter type whose value is intimately linked to the triggering of events for Watchers to consume. Event has a Boolean value, which when set to True triggers the associated watchers (as any Parameter does) but then is automatically set back to False.

+

Conversely, if events are triggered directly on a param.Event via .trigger, the value is transiently set to True (so that it’s clear which of many parameters being watched may have changed), then restored to False when the triggering completes. An Event parameter is thus like a momentary switch or pushbutton with a transient True value that normally serves only to launch some other action (e.g. via a param.depends decorator or a watcher), rather than encapsulating the action itself as param.Action does.

+
+
+
class Q(param.Parameterized):
+    e = param.Event()
+    
+    @param.depends('e', watch=True)
+    def callback(self):
+        print(f'e=={self.e}')
+        
+q = Q()
+q.e = True
+
+
+
+
+
e==True
+
+
+
+
+
+
+
q.e
+
+
+
+
+
False
+
+
+
+
+
+
+
q.param.trigger('e')
+
+
+
+
+
e==True
+
+
+
+
+
+
+
q.e
+
+
+
+
+
False
+
+
+
+
+
+
+

Async executor#

+

Param’s events and callbacks described above are all synchronous, happening in a clearly defined order where the processing of each function blocks all other processing until it is completed. Watchers can also be used with the Python3 asyncio async/await support to operate asynchronously. To do this, you can define param.parameterized.async_executor with an asynchronous executor that schedules tasks on an event loop from e.g. Tornado or the asyncio library, which will allow you to use coroutines and other asynchronous functions as .param.watch callbacks.

+

As an example, you can use the Tornado IOLoop underlying this Jupyter Notebook by putting events on the event loop and watching for results to accumulate:

+
+
+
import param, asyncio, aiohttp
+from tornado.ioloop import IOLoop
+
+param.parameterized.async_executor = IOLoop.current().add_callback
+
+class Downloader(param.Parameterized):
+    url = param.String()
+    results = param.List()
+    
+    def __init__(self, **params):
+        super().__init__(**params)
+        self.param.watch(self.fetch, ['url'])
+
+    async def fetch(self, event):
+        async with aiohttp.ClientSession() as session:
+            async with session.get(event.new) as response:
+                img = await response.read()
+                self.results.append((event.new, img))
+
+f = Downloader()
+n = 7
+for index in range(n):
+    f.url = f"https://picsum.photos/800/300?image={index}"
+
+f.results
+
+
+
+
+
[]
+
+
+
+
+

When you execute the above cell, you will normally get [], indicating that there are not yet any results available.

+

What the code does is to request 10 different images from an image site by repeatedly setting the url parameter of Downloader to a new URL. Each time the url parameter is modified, because of the self.param.watch call, the self.fetch callback is invoked. Because it is marked async and uses await internally, the method call returns without waiting for results to be available. Once the awaited results are available, the method continues with its execution and a tuple (image_name, image_data) is added to the results parameter.

+

If you need to have all the results available (and have an internet connection!), you can wait for them:

+
+
+
print("Waiting: ", end="")
+while len(f.results)<n:
+    print(f"{len(f.results)} ", end="")
+    await asyncio.sleep(0.05)
+    
+[t[0] for t in f.results]
+
+
+
+
+
Waiting: 0 
+
+
+
0 
+
+
+
0 0 
+
+
+
0 
+
+
+
0 
+
+
+
0 0 
+
+
+
0 
+
+
+
0 
+
+
+
0 
+
+
+
['https://picsum.photos/800/300?image=5',
+ 'https://picsum.photos/800/300?image=0',
+ 'https://picsum.photos/800/300?image=4',
+ 'https://picsum.photos/800/300?image=6',
+ 'https://picsum.photos/800/300?image=3',
+ 'https://picsum.photos/800/300?image=2',
+ 'https://picsum.photos/800/300?image=1']
+
+
+
+
+

This while loop iterates until all results are available, printing a count of results so far each time through the loop. Processing is done during the asyncio.sleep call, which returns control to the IOLoop for that length of time, and then the while loop checks to see if processing is done yet. Once it’s done, the list of URLs downloaded is displayed, and you can see from the ordering (unlikely to be sequential) that the downloading was done asynchronously. You can find out more about programming asynchronously in the asyncio docs.

+
+
+

Applying these techniques to your own code#

+

As you can see, there is extensive support for watching for events on Parameters, whether you use the low-level Watcher interface or the high-level @param.depends interface. As usual when multiple APIs are provided, it’s a good idea to start with the high-level interface, and only drop down to the low-level watching approach if you need the additional power and control and are able to accept the corresponding complexity. The asynchronous approach is then only needed for very specific applications where you want your code to be decoupled from an external system. Most people can simply use @param.depends to cover all their needs for interaction between Parameters and for computation that depends on Parameters.

+
+
+
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/user_guide/Dynamic_Parameters.html b/user_guide/Dynamic_Parameters.html new file mode 100644 index 0000000..44481ea --- /dev/null +++ b/user_guide/Dynamic_Parameters.html @@ -0,0 +1,1797 @@ + + + + + + + + + + + + Dynamic parameter values — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

Dynamic parameter values#

+

When developing your own Python code using Parameters, there are a variety of different programming models you can use:

+
    +
  1. Parameters as fancy Python attributes: making use of Param’s semantic type checking, inheritance of default values and docstrings, etc., but not using any dynamic or event-handling features of Param. When Parameter values need to change, users change them explicitly, using their own Python code in separate methods and functions invoked from outside of Param.

  2. +
  3. “Push” model: Using Param’s Dependencies and Watchers so that Param invokes user-written code to change Parameter values based on events that Param detects (typically chaining from changes in some other parameter values). A “push” model is typical for event-driven GUI applications, where a user interacts with a GUI widget to change some Parameter value, prompting Param to execute chained dependencies in response.

  4. +
  5. “Pull” model: Using Dynamic parameter values (described here) where the value of each dynamic parameter is computed when the parameter is read, potentially computing it from some global state values. A “pull” model is typical for simulations with a global clock, making it easy to use value a1 at time 1, value a2 at times 2-100, value a3 for 100-, etc.

  6. +
+

Each of these models has advantages and disadvantages that make them appropriate for different situations, so it’s important to understand all three models so that you can choose the right one(s) for your system. Here, we’ll discuss the third model, using Dynamic parameters.

+
+

param.Dynamic#

+

A Dynamic parameter of type t is one that accepts either a value of type t, or a callable returning a value of type t. If a user passes a callable, the callable will be invoked to get the actual value when the parameter value is accessed. All of Param’s numeric parameter types are Dynamic because their base class param.Number inherits from param.Dynamic. New non-numeric types can be defined and made dynamic by inheriting from param.Dynamic, and having dynamic string and selector parameters would be a nice addition to the current dynamic numeric parameter support.

+

To see how it works, let’s make a Parameterized class with some numeric Parameters:

+
+
+
import param, random
+
+class P(param.Parameterized):
+    i = param.Integer(2)
+    j = param.Integer(5)
+    k = param.Integer(8)
+    x = param.Number(-13.6)
+
+P(i=6, x=9.8)
+
+
+
+
+
P(i=6, j=5, k=8, name='P00002', x=9.8)
+
+
+
+
+

Here we can set p.i and p.x to any supported numeric values, illustrating programming model 1. But we can also set them to dynamic values, for model 3:

+
+
+
p = P(i=lambda: random.randint(35,99), x=lambda: random.random())
+p
+
+
+
+
+
P(i=<function <lambda> at 0x7f5b5ceb3550>, j=5, k=8, name='P00003', x=<function <lambda> at 0x7f5b5ceb3040>)
+
+
+
+
+
+
+
p.i, p.i, p.i
+
+
+
+
+
(64, 94, 43)
+
+
+
+
+
+
+
p.x, p.x, p.x
+
+
+
+
+
(0.743899585374881, 0.09120587218600318, 0.7089640882129363)
+
+
+
+
+

As you can see, each time you access a parameter with a dynamic value, it computes a new value and returns it. If you want to inspect the current value without changing it, you can use a special method for that:

+
+
+
p.param.inspect_value('x'), p.param.inspect_value('x'), p.param.inspect_value('x')
+
+
+
+
+
(0.7089640882129363, 0.7089640882129363, 0.7089640882129363)
+
+
+
+
+

Of course, dynamic parameters don’t have to be random; e.g. you can set a parameter to a counter:

+
+
+
class Count:
+    def __init__(self, start=0):
+        self._count=start
+    
+    def __call__(self):
+        self._count += 1
+        return self._count
+    
+c = Count()
+
+p.j = c
+p.j, p.j, p.j
+
+
+
+
+
(1, 2, 3)
+
+
+
+
+
+
+

Using a global time variable#

+

As you can see, dynamic parameters are very dynamic by default, changing every single time they are accessed. What if you want a “somewhat dynamic” value that changes only in certain well-defined situations? For instance, what if you are running a simulation, and you want a new dynamic value whenever time t changes, but otherwise the value should be constant so that no matter how many times the parameter is read at that time t, the result is the same? Or you are running a training or annealing or sampling or similar process that has many different iterations or runs, and you want values to change only when the iteration or run number changes, and otherwise to have the same value for a given iteration or run?

+

To support simulations and other applications controlled by a central counter or state value like this, Dynamic supports a time_dependent mode where new values will be generated only if param.Dynamic.time_fn has changed in value since a number was last generated:

+
+
+
param.Dynamic.time_dependent = True
+
+p.i, p.i, p.i
+
+
+
+
+
(45, 45, 45)
+
+
+
+
+

time_fn is a callable object that will return the current value if called:

+
+
+
param.Dynamic.time_fn()
+
+
+
+
+
0
+
+
+
+
+

time_fn can be incremented using += or changed to a specific value by calling with that value:

+
+
+
param.Dynamic.time_fn +=1
+p.i, p.i, p.i
+
+
+
+
+
(81, 81, 81)
+
+
+
+
+
+
+
param.Dynamic.time_fn +=10
+p.i, p.i, p.i
+
+
+
+
+
(72, 72, 72)
+
+
+
+
+
+
+
param.Dynamic.time_fn(6)
+param.Dynamic.time_fn()
+
+
+
+
+
6
+
+
+
+
+
+
+
p.i, p.i, p.i
+
+
+
+
+
(90, 90, 90)
+
+
+
+
+

The global time_fn provides a convenient way to compute values that are fixed functions of the time value:

+
+
+
p.k = lambda: 100+param.Dynamic.time_fn()**2
+p.k
+
+
+
+
+
136
+
+
+
+
+
+
+
param.Dynamic.time_fn +=10
+p.k
+
+
+
+
+
356
+
+
+
+
+
+
+
# Reset to the default, to support out of order execution of this notebook
+param.Dynamic.time_dependent = False 
+
+
+
+
+

See help(param.Time) for detailed information about using the time_fn, including:

+
    +
  • how to use time_fn as a context manager to test results at different times without disrupting the current time

  • +
  • how and why to use time types other than the integer default

  • +
  • how to set an upper limit on the time to bound a simulation run

  • +
  • how to declare the time units and time label

  • +
+

The time_fn is not required to be of type param.Time, but a lot of the features here do depend on that particular model of time.

+

If there are any Parameterized objects that should not respect the global time value or should respect a different time value, you can call obj.param.set_dynamic_time_fn() to override the time on those objects and any of their subobjects.

+

You can see topographica for an example of a complex simulator built on Param’s time support, including a general-purpose event-driven simulation engine capable of simulating any phenomena that can be simulated by updating at discrete times (whether on a fixed global timebase or not).

+
+
+
#help(param.Time)
+
+
+
+
+
+
+

Numbergen#

+

As you can see above, you can pass any callable object to a Dynamic parameter, including unnamed functions (lambdas), named functions, and custom objects with a __call__ method. However, each of those approaches has limitations:

+
    +
  • lambdas cannot easily be pickled for saving and restoring state (though see cloudpickle for an alternative to pickle that does support lambdas)

  • +
  • named functions don’t support internal state and need to be stored in a named module somewhere for them to be picklable, potentially resulting in a large number of one-off functions to keep track of

  • +
  • making a new object with a __call__ method is verbose and error-prone, and again needs to be stored in a formal module if it is to be picklable.

  • +
+

To make using Dynamic parameters more convenient, Param includes a separate module Numbergen that provides ready-to-use, picklable, composable, and interchangeable callable objects producing numeric values. Numbergen relies only on Param and the Python standard library, so it should be easy to add to any project.

+

Numbergen objects are designed to work seamlessly as Dynamic parameter values, providing easy access to various temporal distributions, along with tools for combining and configuring number generators without having to write custom functions or classes. Moreover, because all of these objects are Parameterized objects sharing the same usage interface (each provides a numeric value when called, regardless of how many or which parameters are required to configure that distribution), using them together with Param’s Dynamic support provides a huge amount of power over the values parameters take over time, without requiring any extra complexity in your program. Without Dynamic support and numbergen, your Parameterized classes could of course provide their own support for e.g. a normal random distribution by accepting a mean and variance, but it would then be limited to that specific random distribution, whereas Dynamic parameters can accept any current or future number generator object as configured by a user for their own purposes, neatly separating your Parameterized’s requirements (“a positive integer value”) from the user’s requirements (“let’s see what happens when the value starts at 1 and doubles every iteration”).

+

Numbergen objects all inherit from ng.NumberGenerator, which defines the callable interface and adds operator support as described below. Each type of object then further inherits from either TimeAware (having basic time support) or TimeDependent (TimeAware objects having values that are a strict function of time).

+
+

TimeDependent number generators#

+

If you have a global clock, TimeDependent number generators are easy to reason about: their value is a strict function of the time value returned by their time_fn parameter. If the generator has a value v at time t, then if time is advanced by 10 units to t+10, rolled back 5 units to t+5, and rolled back 5 more units to t, the value of the generator will again be v. These generators typically calculate their values directly from the time_fn value. TimeDependent objects provide a time_dependent parameter that is always True; the only mode they support is to be dependent on the global time. TimeDependent number generators include:

+
    +
  • ng.ScaledTime(factor=1.0): Simple multiplicative function of the global time value.

  • +
  • ng.ExponentialDecay(starting_value=1.0, ending_value=0.0, time_constant=10000, base=e): Returns starting_value*base^(-time_fn()/time_constant).

  • +
  • ng.BoxCar(onset=0.0, duration=None): 1.0 in the exclusive interval (onset, onset+duration); zero at all other times. Default is a step function with no offset.

  • +
  • ng.SquareWave(onset=0.0, duration=1.0, off_duration=None): Alternating between 1.0 and 0.0 starting at the onset with a frequency (duration+off_duration) with a duty cycle determined by duration:off_duration (50% by default; off_duration defaults to the initial on duration).

  • +
+

To demonstrate these objects, let’s write a helper function that samples the distribution at different time values:

+
+
+
import numbergen as ng
+import pandas as pd
+
+param.Dynamic.time_dependent = True
+pd.options.display.precision=3
+
+def timesample(ng, ts=range(0,10), time_fn = param.Dynamic.time_fn):
+    ss = []
+    for t in ts:
+        time_fn(t)
+        s = ng()
+        ss += [(t,s)]
+    df = pd.DataFrame(ss, columns=['t','s']).T
+    return df.style.set_caption(ng.param.pprint(unknown_value=None))
+
+
+
+
+

Now we can see how each of these objects behaves as t changes:

+
+
+
timesample(ng.ScaledTime(factor=2.0))
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ScaledTime(factor=2.0)
 0123456789
t0.0000001.0000002.0000003.0000004.0000005.0000006.0000007.0000008.0000009.000000
s0.0000002.0000004.0000006.0000008.00000010.00000012.00000014.00000016.00000018.000000
+
+
+
+
+
timesample(ng.ExponentialDecay(time_constant=2, base=4))
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ExponentialDecay(base=4, time_constant=2)
 0123456789
t0.0000001.0000002.0000003.0000004.0000005.0000006.0000007.0000008.0000009.000000
s1.0000000.5000000.2500000.1250000.0625000.0312500.0156250.0078120.0039060.001953
+
+
+
+
+
timesample(ng.BoxCar(onset=0.0, duration=3))
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
BoxCar(duration=3)
 0123456789
t0.0000001.0000002.0000003.0000004.0000005.0000006.0000007.0000008.0000009.000000
s0.0000001.0000001.0000001.0000000.0000000.0000000.0000000.0000000.0000000.000000
+
+
+
+
+
timesample(ng.SquareWave(onset=0.0, duration=1.0, off_duration=2.0))
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SquareWave(off_duration=2.0)
 0123456789
t0.0000001.0000002.0000003.0000004.0000005.0000006.0000007.0000008.0000009.000000
s1.0000000.0000000.0000001.0000000.0000000.0000001.0000000.0000000.0000001.000000
+
+
+
+
+

TimeAware random number generators#

+

A TimeAware object also has access to a time_fn and has a time_dependent parameter, but either sets time_dependent=False (indicating that values are never a strict function of time) or allows either True or False (switching into and out of a time dependent mode). All current TimeAware NumberGenerator objects are random number generators that support both possible values of time_dependent. For time_dependent=False (the default), they return a new value on each call, while for time_dependent=True, they return pseudorandom values that follow the indicated distribution but are also a strict function of the time, in that the same number will be returned for a given time value even if time skips ahead or backwards.

+

These random values are thus very tightly controlled to allow reproducible, repeatable results, with values determined by both a seed value (to choose the overall set of random values) and by the current time. Effectively, when time_dependent=True, these numbers provide a random value seeded by the generator’s name parameter, the global param.random_seed, the seed parameter of the NumberGenerator, and the NumberGenerator’s current time_fn() value. The resulting generated values should be the same for a given object and a given time_fn value, even across platforms and machine-word sizes (see the Hash, TimeAwareRandomState, and RandomDistribution classes for more details).

+

For best results, you should provide an explicit unique name to any such generator and preserve that name over time, so that results will be reproducible across program runs. By default, the underlying random numbers are generated using Python’s random module (which see for details of the number generation), but you can substitute an instance of numpy.random.RandomState or similar compatible object for self.random_generator for higher performance or to generate time-dependent array values.

+

RandomDistributions (all TimeAware and supporting time_dependent) include:

+
    +
  • ng.UniformRandom(lbound=0.0, ubound=1.0): Uniform random float in the range [lbound, ubound).

  • +
  • ng.UniformRandomOffset(mean=0, range=1.0): Same as UniformRandom, but returns a random float in the range [mean - range/2, mean + range/2).

  • +
  • ng.UniformRandomInt(lbound=0, ubound=1000): Uniform random integer in the (inclusive) range [lbound, ubound].

  • +
  • ng.Choice(choices=[0,1]): Random value from a provided list of choices.

  • +
  • ng.NormalRandom(mu=0.0, sigma=1.0): Normally distributed (Gaussian) random number with mean mu and standard deviation sigma.

  • +
  • ng.VonMisesRandom(mu=0,kappa=1): Circularly normal distributed random number centered around mu with inverse variance kappa; for kappa=0 the result is uniformly distributed from 0 to 2*pi, and for narrow kappa it approaches the normal distribution with variance 1/kappa.

  • +
+
+
+
timesample(ng.UniformRandom(lbound=0.0, ubound=10.0))
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
UniformRandom(ubound=10.0)
 0123456789
t0.0000001.0000002.0000003.0000004.0000005.0000006.0000007.0000008.0000009.000000
s0.9515415.6233812.8718643.9881043.0484566.4733053.6701726.9761450.3527638.073987
+
+
+
+
+
timesample(ng.UniformRandomOffset(mean=100, range=3))
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
UniformRandomOffset(mean=100, range=3)
 0123456789
t0.0000001.0000002.0000003.0000004.0000005.0000006.0000007.0000008.0000009.000000
s99.032228100.352862100.97596398.507375101.45495599.04380799.292438100.832103100.87464499.390498
+
+
+
+
+
timesample(ng.UniformRandomInt(lbound=0, ubound=1000))
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
UniformRandomInt()
 0123456789
t0123456789
s8594125460837914173582157409
+
+
+
+
+
timesample(ng.Choice(choices=[3.1, -95, 7]))
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Choice(choices=[3.1,-95,7])
 0123456789
t0.0000001.0000002.0000003.0000004.0000005.0000006.0000007.0000008.0000009.000000
s3.1000007.0000007.0000003.100000-95.0000007.000000-95.0000003.100000-95.000000-95.000000
+
+
+
+
+
timesample(ng.NormalRandom(mu=50.0, sigma=5.0))
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NormalRandom(mu=50.0, sigma=5.0)
 0123456789
t0.0000001.0000002.0000003.0000004.0000005.0000006.0000007.0000008.0000009.000000
s48.59448947.52560551.64926242.70483844.36583938.12308448.51544744.41056753.17745056.113971
+
+
+
+
+
timesample(ng.VonMisesRandom(mu=0, kappa=500)) # small variance around 0 (aka 2pi)
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
VonMisesRandom(kappa=500)
 0123456789
t0.0000001.0000002.0000003.0000004.0000005.0000006.0000007.0000008.0000009.000000
s0.0094316.2533640.0057426.2830480.0333166.2661986.2508740.0240636.2347606.223010
+
+
+
+
+

Operations on number generators#

+

Numbergen also provides a couple of NumberGenerators that accept other NumberGenerator objects and filter or modify their values:

+
    +
  • ng.TimeSampledFn(period=1.0, offset=1.0, fn=None): Discretizes the given time-dependent NumberGenerator to give discrete values held constant over the given period, changing a continuous function of time into a series of discrete steps starting at the indicated offset and changing at the indicated period.

  • +
  • ng.BoundedNumber(generator=None, bounds=(None,None)): Wrapper around another number generator (any callable returning a number) that silently crops the result to the given bounds.

  • +
+

It also provides a set of unary (- + abs()) and binary (+ - * % ** / //) mathematical operators that make it simple to adapt the output for usage in practice without having to define one-off functions. For instance:

+
+
+
timesample(-abs(ng.ScaledTime(factor=2.0)+1)//4)
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
BinaryOperator()
 0123456789
t0.0000001.0000002.0000003.0000004.0000005.0000006.0000007.0000008.0000009.000000
s-1.000000-1.000000-2.000000-2.000000-3.000000-3.000000-4.000000-4.000000-5.000000-5.000000
+
+
+
+
+
timesample(ng.UniformRandom()%0.2)
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
BinaryOperator()
 0123456789
t0.0000001.0000002.0000003.0000004.0000005.0000006.0000007.0000008.0000009.000000
s0.1220120.1673960.1951020.0296980.0584290.1442280.0139710.1703240.1681700.096172
+
+
+
+
+
timesample(2*ng.SquareWave()-1)
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
BinaryOperator()
 0123456789
t0.0000001.0000002.0000003.0000004.0000005.0000006.0000007.0000008.0000009.000000
s1.000000-1.0000001.000000-1.0000001.000000-1.0000001.000000-1.0000001.000000-1.000000
+
+
+
+
+
+

Using numbergen objects for parameter values#

+

Any of the above objects can be supplied for any param.Number Parameter type. For instance, instead of the lambdas in the first examples in this guide, you can use Numbergen objects:

+
+
+
param.Dynamic.time_dependent = False
+
+p = P(i=ng.UniformRandomInt(lbound=35, ubound=99), 
+      x=ng.UniformRandom())
+
+p.i, p.i, p.i
+
+
+
+
+
(70, 56, 93)
+
+
+
+
+
+
+
p.x, p.x, p.x
+
+
+
+
+
(0.9614164612777242, 0.4729860797140646, 0.7161196189622282)
+
+
+
+
+

Notice that the decision to use a particular distribution is up to the user of class P, not the author of P. The author of P just needs to know that i will be an integer and that x will be a float (with bounds if specified); the user is then free to set those values to be static or any type of dynamic value as needed. Using Param with this “pull” model thus provides users with easy ways to control how parameters change their value over time (for some model of time), without additional work by the Parameterized class author. You can see extensive examples of this approach at the imagen website, which shows how Numbergen objects can be used to create flexible streams of generated image objects without needing any special support for such streams in the Parameterized objects in that library.

+
+
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/user_guide/How_Param_Works.html b/user_guide/How_Param_Works.html new file mode 100644 index 0000000..88ac1e1 --- /dev/null +++ b/user_guide/How_Param_Works.html @@ -0,0 +1,885 @@ + + + + + + + + + + + + How Param Works — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

How Param Works#

+

Param seamlessly makes Python attributes have a much richer set of behaviors than they would otherwise, at once both more powerful (with automatic dynamic behavior) and more tightly controlled by the class author. It is natural to wonder how Param achieves this, especially given that it is a normal pure-Python library, not an alternative implementation of Python or a pre-processor. The answer is that Param makes extensive use of Python language features that allow tailoring the behavior of attribute getting and setting in sophisticated ways. You don’t need to read any of the material on this page to use Param successfully, but it might help you understand what’s going on “under the hood” for debugging or optimizing complex situations or for extending Param.

+
+

Descriptors#

+

A Parameter object is a type of Python “descriptor”, i.e., an object that implements custom __get__ and/or __set__ behavior. When a descriptor is an attribute of a class, Python will invoke those custom methods instead of simply getting and setting the actual value of the attribute (i.e., the Parameter object). The Python descriptor docs explain this process in detail, but briefly, let’s consider a simple descriptor that returns how many times it has been accessed:

+
+
+
class Count:
+    def __init__(self, start=0):
+        self._count = start
+    
+    def __get__(self, obj, objtype=None):
+        self._count += 1
+        return self._count
+
+
+
+
+
+
+
class C:
+    x = 5
+    y = Count(0)
+
+c = C()
+
+c.x, c.x, c.x, c.y, c.y, c.y
+
+
+
+
+
(5, 5, 5, 1, 2, 3)
+
+
+
+
+

As you can see, class attributes x and y here can both be used the same way, but x is a normal Python attribute, returning the fixed value 5 that was set on the class, while y is a descriptor and returns a computed value when accessed (rather than returning itself as you might think from the syntax), and thus gives a different value each time. Parameters are much more complex than the above example, but this descriptor support provides the underlying mechanism for having full-featured attribute behavior like dynamic values, bounds checking, and so on.

+
+
+

Slots#

+

As described in the Parameters docs, Parameters can store a rich collection of metadata about each parameter. Storing a full object and associated dictionary of metadata for each class and instance attribute could get expensive (i.e., slow and using a lot of memory), so Parameters are implemented using slots. A slot is like a normal Python attribute, but instead of being stored in the convenient and flexible but slow __dict__ attribute of the object, slots are stored in a fixed-size data structure __slots__ that works like a C struct. __slots__ reserves just enough space to store these attributes, which can be accessed instantaneously rather than requiring a dictionary lookup (hash table search).

+

Using __slots__ requires special support for operations to copy and restore Parameters (e.g. for Python persistent storage pickling); see __getstate__ and __setstate__. A Parameter defines at least these slots, with additional slots added for each subclass:

+
__slots__ = ['name', 'default', 'doc',
+            'precedence', 'instantiate', 'constant', 'readonly',
+            'pickle_default_value', 'allow_None', 'per_instance',
+            'watchers', 'owner', '_label']
+
+
+

In most cases, you can just treat a Parameter’s existing slots like attributes of the Parameter class; they work just the same as regular attributes except for speed and storage space. However, if you add a new attribute to a Parameter class, you have to make sure that you also add it to the __slots__ defined for that Parameter class, or you’ll either get an error or else the Parameter will get an unnecessary full __dict__ object just to hold the one new attribute.

+
+
+

Metaclasses#

+

Another way Parameter and Parameterized differ from ordinary Python classes is that they specify a special metaclass that determines how they behave. Just like you instantiate a Python class to get a Python object, you instantiate a Python metaclass to get a Python class. Most classes are instances of the default metaclass named type, but with a custom metaclass, you can define how every Python class with that metaclass will behave, at a fundamental level.

+

The ParameterMetaclass is fairly simple, mainly overriding docstrings so that help(someparam) gives the declared documentation for the Parameter instance, rather than the less-useful docstring for the underlying class that it would otherwise display. This behavior is convenient, but not essential to the operation of Param.

+

ParameterizedMetaclass, on the other hand, defines a lot of the behavior behind Param’s features. In particular, the metaclass implements the behavior for getting and setting parameter values at the class level, similar to how a descriptor controls such behavior at the instance level. Without the metaclass, setting the value of a class attribute to a scalar like 5 would wipe out the Parameter object rather than updating the default value. The metaclass thus performs the same role at the class level as descriptors do at the instance level. Descriptors allow setting the value of an instance attribute without overriding the Parameter object on that instance, and the metaclass allows setting the value of a class attribute without overridding the Parameter object on the class. All told, the ParameterizedMetaclass handles:

+
    +
  • allowing Parameter default values to be set at the class level (as just described),

  • +
  • supporting inheriting Parameter objects from superclasses,

  • +
  • instantiating parameter default values (if needed)

  • +
  • populating the name slot of each Parameter by its attribute name in the class,

  • +
  • reporting whether a class has been declared to be abstract (useful for ignoring it in selectors),

  • +
  • various bookkeeping about dependencies and watchers,

  • +
  • generating docstrings at the class level for each Parameter in the class so that help(parameterizedclass) displays not just the class docstring but also information about the Parameters in it (or in superclasses)

  • +
+

Thus much of how Param works depends on ParameterizedMetaclass.

+
+
+

Custom attribute access#

+

The above mechanisms let Param customize attribute access for dynamic behavior and control over user settings. As an example of how this all fits together, consider the following code:

+
+
+
from param import Parameterized, Parameter
+
+class A(Parameterized):
+    p = Parameter(default=1, per_instance=False, instantiate=False)
+
+a1 = A()
+a2 = A()
+
+
+
+
+

Here, a1 and a2 share one Parameter object (A.__dict__['p']), because per_instance is False:

+
+
+
A.__dict__['p'] is a1.param.p is a2.param.p
+
+
+
+
+
True
+
+
+
+
+

The default (class-attribute) value of p is stored in this Parameter object (A.__dict__['p'].default), but is accessible as A.p due to the Parameter being a descriptor:

+
+
+
A.__dict__['p'].default
+
+
+
+
+
1
+
+
+
+
+
+
+
A.p
+
+
+
+
+
1
+
+
+
+
+

If the value of p is set on a1, a1’s value of p is stored in the a1 instance itself, in a dictionary named values under the private namespace _param__private:

+
+
+
a1.p = 2
+a1._param__private.values['p']
+
+
+
+
+
2
+
+
+
+
+

When a1.p is requested, a1._param__private.values['p'] is returned. When a2.p is requested, p is not found in a2._param__private.values, so A.__dict__['p'].default (i.e. A.p) is returned instead:

+
+
+
a2.p
+
+
+
+
+
1
+
+
+
+
+

Because the value for a2.p is returned from A.p, changing A.p will affect a2.p, but not a1.p since it has its own independent value:

+
+
+
A.p = 3
+a2.p, a1.p
+
+
+
+
+
(3, 2)
+
+
+
+
+

If p was not defined in A but was defined in a superclass, the value found in that superclass would be returned instead.

+

You can re-execute the above code changing to per_instance=True and/or instantiate=True on Parameter p and see how the behavior differs. With per_instance=True (which would normally be the default), a1 and a2 would each have independent copies of the Parameter object, and with instantiate=True, each instance would get its own copy of the class’s default value, making it immune to later changes at the class level.

+
+
+
+

Other notes#

+

Once we have Parameter descriptors and the metaclasses, there is relatively little left for the Parameterized class itself to do:

+
    +
  • implementing the rest of dependencies and watchers

  • +
  • providing a constructor that lets you set instance parameters

  • +
  • instantiating and providing the .param accessor for invoking methods and accessing the Parameter objects

  • +
  • handling state saving and restoring (pickling)

  • +
+

And that’s it for the core of Param! There are other behaviors implemented at the level of specific Parameters, but those are typically localized and can be understood by reading the class docstring for that Parameter type.

+
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/user_guide/Logging_and_Warnings.html b/user_guide/Logging_and_Warnings.html new file mode 100644 index 0000000..11dc3fe --- /dev/null +++ b/user_guide/Logging_and_Warnings.html @@ -0,0 +1,868 @@ + + + + + + + + + + + + Logging and Warnings — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

Logging and Warnings#

+

Parameterized objects provide methods for displaying logging messages and warnings in a way that can be controlled and redirected globally using the standard Python logging module (see the logging cookbook). Compared to using a Python logger directly, using these methods inside your Parameterized class helps users by making the messages consistent, each prepending with information about the Parameterized object where the call was made so that your users can understand what the message indicates.

+

By default, a Python logger named param will be instantiated to do the logging, but another logger can be supplied by setting param.parameterized.logger to it after importing param.parameterized.

+
+

Writing log messages#

+

Each logging message has an associated logging level that indicates how severe a condition is being described (DEBUG, VERBOSE, INFO (aka “message”), WARNING, ERROR, or CRITICAL). These levels are as defined by the logging module, except for the addition of VERBOSE as a level intermediate between DEBUG (internal debugging information) and INFO (user-relevant non-error messages).

+

The typical way to print a message is to call .param.log() with one of the following logging levels:

+
    +
  • .param.log(param.DEBUG, ...): Detailed debugging information, not displayed onscreen by default.

  • +
  • .param.log(param.VERBOSE, ...): Additional sometimes-useful information, not displayed onscreen by default.

  • +
  • .param.log(param.INFO, ...): Informative message, displayed onscreen by default.

  • +
  • .param.log(param.WARNING, ...): Warning of an unexpected or inappropriate but non-fatal condition, displayed onscreen by default.

  • +
+

For convenience and to allow eventual integration with the Python warnings module, .param.warning( is available as an alias for .param.log(param.WARNING,:

+
    +
  • .param.warning(...): Warning of an unexpected or inappropriate but non-fatal condition, displayed onscreen by default.

  • +
+

The arguments accepted in each case are the same as those of logging.debug(). Specifically, each call is like .param.debug(msg, *args, **kw), where msg is an old-style (‘%’) format string and the args and kwargs will be merged with that format string. E.g.:

+
+
+
import param
+
+desired = 1
+actual = 5
+
+param.main.param.log(param.INFO, "Welcome!")
+param.main.param.log(param.VERBOSE, "Local variables: %s", locals())
+param.main.param.log(param.WARNING, "Value %02d is not %d", actual, desired)
+param.main.param.warning("Value %02d is not %d", actual, desired)
+
+
+
+
+
INFO:param.main: Welcome!
+
+
+
WARNING:param.main: Value 05 is not 1
+
+
+
WARNING:param.main: Value 05 is not 1
+
+
+
+
+

Here we’ve used the default global Parameterized object param.main, useful for generic module-level messages, but more often you would make a call like self.param.log() inside a Parameterized class instead. You can see that the messages are each prefixed by the logging level, param (the name of the default logger), and the name of this object (main in this case). You can also see that, by default, verbose messages are not actually printed.

+

You may wonder (a) why the formatting string is “old style” , and (b) why the formatting values “actual, desired” are not combined directly with the formatting string. I.e., why not just use a Python3 f-string, like:

+
+
+
param.main.param.log(param.WARNING, f"Value {actual:02} is not {desired}") # Discouraged!
+
+
+
+
+
WARNING:param.main: Value 05 is not 1
+
+
+
+
+

The answer is that particularly for debug and verbose messages that could occur inside frequently executed code, we want logging to be “lazy”, in that we do not want to render a string representation for actual, desired, etc. unless we are actually printing the message. If we use an f-string or any other locally formatted string, the string formatting will be done whether or not the message will be displayed, potentially causing drastic slowdowns in your code. For instance, in the code above, the entire locals() dictionary would be iterated over, printed to strings. Of course, since the message isn’t being printed in that case, the entire format string would then be discarded, greatly slowing down the code without producing any output. To avoid that, the logging module has to defer the string substitution and handle that itself, and it was written before Python3, so it only supports old-style substitution. So, even though it is more awkward, it is highly recommended to use this old-style, lazy string formatting support.

+
+
+

Controlling the logging level#

+

You can use the param.parameterized.logging_level context manager to temporarily reduce or elevate the logging level while you execute code:

+
+
+
with param.logging_level('CRITICAL'):
+    param.main.param.log(param.INFO, "Message 1")
+    param.main.param.log(param.VERBOSE, "Verbose 1")
+
+
+
+
+
+
+
with param.logging_level('DEBUG'):
+    param.main.param.log(param.INFO, "Message 2")
+    param.main.param.log(param.VERBOSE, "Verbose 2")
+
+
+
+
+
INFO:param.main: Message 2
+
+
+
VERBOSE:param.main: Verbose 2
+
+
+
+
+

You can also set the value more globally (and permanently) on the logger object:

+
+
+
param.get_logger().setLevel(param.DEBUG)
+
+
+
+
+
+
+
param.main.param.log(param.INFO, "Message 2")
+param.main.param.log(param.VERBOSE, "Verbose 2")
+
+
+
+
+
INFO:param.main: Message 2
+
+
+
VERBOSE:param.main: Verbose 2
+
+
+
+
+

For testing, continuous integration (CI), or other specific applications, you can also set param.parameterized.warnings_as_exceptions = True, which will cause your program to raise an exception the first time it encounters any warning.

+
+
+
+

Controlling the formatting of log messages#

+

The Python logging module provides many options for configuring how the log messages are generated. For complete control, you can instantiate your own logger and set param.parameterized.logger to it after importing param.parameterized.

+

A hook is provided for the relatively common case when you want to prefix each message with the time of day, a progress indication, a simulator time, or some other indication of a global state. Specifically, you can set param.parameterized.dbprint_prefix to a callable object returning a string. The object will be called when constructing each message:

+
+
+
from datetime import datetime
+#param.parameterized.warnings_as_exceptions = True
+
+param.parameterized.dbprint_prefix=lambda: str(datetime.now())
+
+param.main.param.warning("Message 4")
+param.main.param.warning("Message 5")
+
+
+
+
+
WARNING:param.main: 2023-09-25 19:54:54.521876: Message 4
+
+
+
WARNING:param.main: 2023-09-25 19:54:54.522554: Message 5
+
+
+
+
+
+

Counting warnings#

+

Typically, a program will abort if an error is encountered, making such a condition hard to miss, but warning messages might be lost in a sea of informational, verbose, or debug messages. Param keeps track of how many times .param.warning(...) (or its alias .param.log(param.WARNING, ...)) has been called, and it is often useful to print out that value at the end of a program run:

+
+
+
print(f"Run completed. {param.parameterized.warning_count} warnings were encountered.")
+
+
+
+
+
Run completed. 5 warnings were encountered.
+
+
+
+
+
+
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/user_guide/Outputs.html b/user_guide/Outputs.html new file mode 100644 index 0000000..6e14b72 --- /dev/null +++ b/user_guide/Outputs.html @@ -0,0 +1,833 @@ + + + + + + + + + + + + Outputs — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

Outputs#

+

Parameters are typically used for the inputs to a Parameterized objects, declaring as precisely as possible which inputs are allowed. You can also declare what outputs are generated by a Parameterized, using @param.output. At present, Param itself does not use output declarations internally, but they can be queried by Param-based programs to allow safe chaining of Parameterized objects into pipelines, such as for the boxflow dataflow programming system or the multi-page pipelines in Panel.

+

@param.output annotates a method on a Parameterized class to declare that it returns one or more outputs of a specified type. As a simple example, this declaration indicates that the given function returns a number:

+
+
+
import param
+
+class P(param.Parameterized):
+    a = param.Number(default=5, bounds=(0, 10))
+    b = param.Number(default=5, bounds=(0, 10))
+
+    @param.output(param.Number)
+    def product(self):
+        return self.a * self.b
+    
+p = P(a=2, b=3)
+p.product()
+
+
+
+
+
6
+
+
+
+
+

If a program wants to know if the output from object p is suitable for connecting to an input of some other object q, it can query this output type:

+
+
+
p.param.outputs()
+
+
+
+
+
{'product': (<param.Number at 0x7f881047cac0>,
+  <bound method P.product of P(a=2, b=3, name='P00002')>,
+  None)}
+
+
+
+
+

This return value is of the form name: (type, method, index), which here indicates that:

+
    +
  • object p generates one output called product

  • +
  • product is of type param.Number

  • +
  • product can be generated by invoking method p.product()

  • +
  • product will be returned directly as a single value by the method (indicated by an index of None; otherwise the index would indicate the position of this particular output in a tuple returned by the method)

  • +
+

An automated program could use this information to decide whether the output from one Parameterized is suitable for connecting to the input of another.

+

The above example is typical, but let’s review the other output declarations accepted by @param.output. The simplest declaration declares the method returns an object of the same name as the method, without any type guarantees:

+
@param.output()
+def product(self): return self.a * self.b
+
+
+

More commonly, a parameter type will be specified as above, indicating that this method returns a value of that type, again defaulting to the method name:

+
@param.output(param.Number())
+def product2(self): return self.a * self.b
+
+
+

The output name can be declared explicitly as a keyword argument if desired, e.g. if the method name is not a suitable output name:

+
@param.output(result=param.Number())
+def __call__(self): return self.a * self.b
+
+
+

Multiple outputs may be declared using keywords mapping from output name to the type:

+
@param.output(prod_num=param.Number(), prod_str=param.String())
+def products(self): 
+    prod = self.a * self.b
+    return prod, str(prod)
+
+
+

@param.output also accepts Python object types, which will be upgraded to a ClassSelector:

+
@param.output(int)
+def int_product(self): return int(self.a * self.b)
+
+
+

We can see these various options in action:

+
+
+
class Q(param.Parameterized):
+    a = param.Number(default=5, bounds=(0, 10))
+    b = param.Number(default=5, bounds=(0, 10))
+
+    @param.output()
+    def product(self): return self.a * self.b
+
+    @param.output(param.Number())
+    def product2(self): return self.a * self.b
+
+    @param.output(result=param.Number())
+    def __call__(self): return self.a * self.b
+
+    @param.output(prod_num=param.Number(), prod_str=param.String())
+    def products(self): 
+        prod = self.a * self.b
+        return prod, str(prod)
+
+    @param.output(int)
+    def int_product(self): return int(self.a * self.b)
+
+q=Q()
+q
+
+
+
+
+
Q(a=5, b=5, name='Q00003')
+
+
+
+
+
+
+
q.param.outputs()
+
+
+
+
+
{'result': (<param.Number at 0x7f88081c8280>,
+  <bound method Q.__call__ of Q(a=5, b=5, name='Q00003')>,
+  None),
+ 'int_product': (<param.ClassSelector at 0x7f88086d0250>,
+  <bound method Q.int_product of Q(a=5, b=5, name='Q00003')>,
+  None),
+ 'product': (<param.parameterized.Parameter at 0x7f881354a720>,
+  <bound method Q.product of Q(a=5, b=5, name='Q00003')>,
+  None),
+ 'product2': (<param.Number at 0x7f88081c81c0>,
+  <bound method Q.product2 of Q(a=5, b=5, name='Q00003')>,
+  None),
+ 'prod_num': (<param.Number at 0x7f88081c8340>,
+  <bound method Q.products of Q(a=5, b=5, name='Q00003')>,
+  0),
+ 'prod_str': (<param.parameterized.String at 0x7f8810483180>,
+  <bound method Q.products of Q(a=5, b=5, name='Q00003')>,
+  1)}
+
+
+
+
+

Here, you can see that there are two outputs from prod_str(), one of type Number and one of type String, and that they are in the order (number, string) in the tuple. The other outputs are all a single result returned directly from that method, with the indicated types (defaulting to Parameter) and names. Annotating outputs in this way can help you build large, flexible systems for connecting Parameterized objects together into larger data or computational structures.

+
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/user_guide/Parameter_Types.html b/user_guide/Parameter_Types.html new file mode 100644 index 0000000..905966e --- /dev/null +++ b/user_guide/Parameter_Types.html @@ -0,0 +1,2089 @@ + + + + + + + + + + + + Parameter types — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

Parameter types#

+

You can get some of the benefit of Param from Parameter and Parameterized alone, such as having constant or readonly parameters, parameter value inheritance, and parameter docstrings. However, you’ll typically want a more specialized Parameter type so that you can enforce type and bounds restrictions and enable suitable behavior specialized for that type of parameter. Param ships with a large set of pre-defined more-specific Parameter types, and additional custom parameters can and should be added for any domain-specific parameter types needed.

+

The predefined types are organized into a class hierarchy where each type is a subclass of Parameter:

+
    +
  • String: String value, optionally constrained by a regular expression

  • +
  • Color: A hex string specifying an RGB color, or a standard named color

  • +
  • Boolean: True or False (or None, if allowed)

    + +
  • +
  • Dynamic: Base class for values that can be set to a callable that returns a concrete value

    +
      +
    • Number: Any type of numeric value

      +
        +
      • Integer: Positive or negative integer value

      • +
      • Magnitude: Positive value in the inclusive range 0.0,1.0

      • +
      • Date: Date or datetime type

      • +
      • CalendarDate: Date (not datetime)

      • +
      +
    • +
    +
  • +
  • Tuple: Python tuple of a fixed length and optional fixed type

    + +
  • +
  • List: A list of objects, potentially of a fixed, min, or max length

    +
      +
    • HookList: A list of callables, for calling user-defined code at a processing stage

    • +
    +
  • +
  • Path: A POSIX-style string specifying the location of a local file or folder

    +
      +
    • Filename: A POSIX-style string specifying the location of a local file

    • +
    • Foldername: A POSIX-style string specifying the location of a local folder

    • +
    +
  • +
  • SelectorBase: Abstract superclass covering various selector parameter types

    +
      +
    • Selector: One object selected out of a provided ordered list of objects

      +
        +
      • FileSelector: One filename selected out of those matching a provided glob

      • +
      • ListSelector: Multiple objects selected out of a provided list of objects

        +
          +
        • MultiFileSelector: Multiple filenames selected out of those matching a provided glob

        • +
        +
      • +
      +
    • +
    • ClassSelector: An instance or class of a specified Python class or superclass

      + +
    • +
    +
  • +
  • Callable: A callable object, such as a function.

    +
      +
    • Action: A callable with no arguments, ready to invoke

    • +
    +
  • +
  • Composite: A list of other attributes or parameters of this class, settable and readable as a group

  • +
+

The full behavior of these types is covered in the Reference Manual. Here we will discuss the major categories of Parameter type and how to use them, including examples of what each type does not allow (labeled with param.exceptions_summarized():). Each of these classes is also suitable for subclassing to create more specialized types enforcing your own specific constraints. After reading about Parameters in general, feel free to skip around in this page and only look at the Parameter types of interest to you!

+
+

Strings#

+
    +
  • param.String: String value, with optional regular expression (regex) constraints

  • +
+

A param.String may be set to any Python string value by default, or it may be constrained to match a provided regular expression regex. Like all other Parameters, it can optionally also allow_None, which will be true by default if the default value is None.

+
+
+
import param
+
+class S(param.Parameterized):
+    s = param.String('Four score', regex='[A-Z][a-z][a-z][a-z ]*')
+
+s = S()
+s.s
+
+
+
+
+
'Four score'
+
+
+
+
+
+
+
with param.exceptions_summarized():
+    s.s = 5
+
+
+
+
+
ValueError: String parameter 'S.s' only takes a string value, not value of <class 'int'>.
+
+
+
+
+
+
+
s.s = 'Forever after'
+
+
+
+
+
+
+
with param.exceptions_summarized():
+    s.s = 'four of spades'
+
+
+
+
+
ValueError: String parameter 'S.s' value 'four of spades' does not match regex '[A-Z][a-z][a-z][a-z ]*'.
+
+
+
+
+
+
+
ip_regex = '^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$'
+email_regex = '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
+
+class I(param.Parameterized):
+    ip_address = param.String('192.1.0.1', regex=ip_regex)
+    email = param.String('example@me.com', regex=email_regex)
+i = I()
+i.ip_address
+
+
+
+
+
'192.1.0.1'
+
+
+
+
+
+
+
i.ip_address="10.0.0.2"
+i.email = "user@gmail.com"
+
+
+
+
+
+
+
with param.exceptions_summarized():
+    i.ip_address='192.x.1.x'
+
+
+
+
+
ValueError: String parameter 'I.ip_address' value '192.x.1.x' does not match regex '^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$'.
+
+
+
+
+
+
+

Colors#

+
    +
  • param.Color: Named color or hex RGB string (with or without a # prefix)

  • +
+

A Color parameter specifies one of the standard web color names or an arbitrary hex RGB string. To support only hex RGB strings, specify allow_named=False.

+

lemonchiffon

+
+
+
class C(param.Parameterized):
+    c = param.Color('#EEFF00')
+
+c = C()
+c.c
+
+
+
+
+
'#EEFF00'
+
+
+
+
+
+
+
c.c = 'lemonchiffon'
+c.c
+
+
+
+
+
'lemonchiffon'
+
+
+
+
+
+
+
with param.exceptions_summarized():
+    c.c = 'puce'
+
+
+
+
+
ValueError: Color parameter 'C.c' only takes RGB hex codes or named colors, received 'puce'.
+
+
+
+
+
+
+
with param.exceptions_summarized():
+    c.c = '#abcdefg'
+
+
+
+
+
ValueError: Color parameter 'C.c' only takes RGB hex codes or named colors, received '#abcdefg'.
+
+
+
+
+
+
+

Booleans#

+
    +
  • param.Boolean: A True or False value (or None, if allow_None is true)

  • +
+

A Boolean may be True or False. Like all other Parameters, it can optionally also allow_None, which will be true by default if the default value is None.

+
+
+
class B(param.Parameterized):
+    b = param.Boolean(True)
+    n = param.Boolean(None)
+
+b = B()
+b.b
+
+
+
+
+
True
+
+
+
+
+
+
+
with param.exceptions_summarized():
+    b.b=1
+
+
+
+
+
ValueError: Boolean parameter 'B.b' must be True or False, not 1.
+
+
+
+
+
+
+
with param.exceptions_summarized():
+    b.b=None
+
+
+
+
+
ValueError: Boolean parameter 'B.b' must be True or False, not None.
+
+
+
+
+
+
+
b.n = True
+b.n = None
+
+
+
+
+
+
+

Numbers#

+
    +
  • param.Number: Python floats, int, and Numpy values.

  • +
  • param.Integer: Python and Numpy integer values.

  • +
  • param.Magnitude: Same as param.Number(..., bounds=(0.0,1.0)).

  • +
  • param.Date: Date or datetime value of type datetime.datetime, datetime.date, or numpy.datetime64.

  • +
  • param.CalendarDate: Date value of type datetime.date.

  • +
+

A Number is the most common type of Parameter. All Numbers in param are of class Dynamic, which allows them to be set not just to a single value but to a value that can repeatedly be drawn from a distribution or a sequence. (See Dynamic Parameters for more information about using these dynamic features, which will not be further discussed here.) Any Number has a default value (potentially None if allowed) and optional bounds.

+

There are two types of bounds: bounds and softbounds. bounds are hard bounds: the parameter must have a value within the specified range. The default bounds are (None,None), meaning there are actually no hard bounds. One or both bounds can be set by specifying a value (e.g. bounds=(None,10) means there is no lower bound, and an upper bound of 10). Bounds are inclusive by default, but exclusivity can be specified for each bound by setting inclusive_bounds (e.g. inclusive_bounds=(True,False) specifies an exclusive upper bound).

+

When not being dynamically generated, bounds are checked whenever a Number is created or set. Using a default value outside the hard bounds, or one that is not numeric, results in an exception. When being dynamically generated, bounds are checked when the value of a Number is requested (since it has no specific numeric value when first set). A generated value that is not numeric, or is outside the hard bounds, results in an exception.

+

A separate set of softbounds is present to indicate the typical range of the parameter, but these bounds are not enforced by Param. Setting the soft bounds allows a user to know what ranges of values are likely to be useful and allows a GUI to know what values to display on sliders for the Number; softbounds are thus suggestions or hints rather than enforced limits.

+

Similarly, an optional step value can be provided to indicate the granularity of this parameter. As for softbounds, Param does not force values to conform to the provided step value, but (if provided) the step can be queried by user code and used for parameter sweeps (starting at the softbounds low and incrementing in value by step until the softbounds high), or by GUI code to determine steps on a settings dial.

+

Several convenience methods for working with bounds are provided:

+
    +
  • get_soft_bounds(): return the soft bounds (or hard bounds, if no soft bounds), for code that needs to know the typical range for this Parameter.

  • +
  • crop_to_bounds(val): crop the provided value to fit into the hard bounds.

  • +
  • set_in_bounds(obj,val): silently crop the given value into the legal range and set to the result, for building an API or user interface that accepts free-form input.

  • +
+

Using Number parameters:

+
+
+
import param
+
+class N(param.Parameterized):
+    n = param.Number(5.6, bounds=(0,None), softbounds=(None,50))
+    i = param.Integer(5, bounds=(0,50))
+    
+a = N()
+a.n=2
+a.n
+
+
+
+
+
2
+
+
+
+
+
+
+
N.param.n.set_in_bounds(a,-10)
+a.n
+
+
+
+
+
0
+
+
+
+
+
+
+
a.param.n.set_in_bounds(a,-5)
+a.n
+
+
+
+
+
0
+
+
+
+
+
+
+
a.param.n.set_in_bounds(a,75)
+a.n
+
+
+
+
+
75
+
+
+
+
+
+
+
a.param.n.get_soft_bounds()
+
+
+
+
+
(0, 50)
+
+
+
+
+
+
+
with param.exceptions_summarized():
+    a.n = -5
+
+
+
+
+
ValueError: Number parameter 'N.n' must be at least 0, not -5.
+
+
+
+
+
+
+
a.n = 500
+a.n
+
+
+
+
+
500
+
+
+
+
+
+
+
with param.exceptions_summarized():
+    a.i=5.7
+
+
+
+
+
ValueError: Integer parameter 'N.i' must be an integer, not <class 'float'>.
+
+
+
+
+
+
+
import datetime
+
+class D(param.Parameterized):
+    d = param.CalendarDate(datetime.date(1900, 1, 1))
+    t = param.Date(datetime.datetime.fromisoformat('2002-12-25T00:00'))
+
+d = D()
+d.d = datetime.date.fromisoformat('2000-01-01')
+d.d
+
+
+
+
+
datetime.date(2000, 1, 1)
+
+
+
+
+
+
+
with param.exceptions_summarized():
+    d.d = 2022
+
+
+
+
+
ValueError: CalendarDate parameter 'D.d' only takes date types.
+
+
+
+
+
+
+
d.t = datetime.date(1900, 1, 1)
+d.t
+
+
+
+
+
datetime.date(1900, 1, 1)
+
+
+
+
+
+
+
with param.exceptions_summarized():
+    d.d = datetime.datetime.fromisoformat('2002-12-25T00:00')
+
+
+
+
+
ValueError: CalendarDate parameter 'D.d' only takes date types.
+
+
+
+
+
+
+

Tuples#

+
    +
  • param.Tuple: Python tuple of a fixed length.

  • +
  • param.NumericTuple: Python tuple of a fixed length, with numeric values.

  • +
  • param.XYCoordinates: Python pair (2-tuple) of numeric values. Same as param.NumericTuple(..., length=2), but semantically representing a 2D coordinate in a plane (e.g. for drawing programs or GUIs)

  • +
  • param.Range: NumericTuple representing a numeric range with optional bounds and softbounds.

  • +
  • param.DateRange: Range where the numeric type is a date or datetime (using same date types as param.Date).

  • +
  • param.CalendarDateRange: Range where the numeric type is a datetime.date.

  • +
+

A tuple Parameter accepts a Python tuple for the value. Tuple parameters have a fixed length, typically set by the default value of the parameter but settable as the length if the default value is None. Only a tuple of the specified length will be accepted when a value is set.

+

There are many tuple types as listed above, accepting either any type, numeric types, datetimes, dates, etc. Range types support bounds, softbounds, inclusive_bounds, and step on the numeric values in the tuple, similar to Number types.

+
+
+
class T(param.Parameterized):
+    t = param.Range((-10,10), bounds=(-100,None), softbounds=(None,100))
+b = T()
+b.t
+
+
+
+
+
(-10, 10)
+
+
+
+
+
+
+
b.t = (50.2,50.3)
+b.t
+
+
+
+
+
(50.2, 50.3)
+
+
+
+
+
+
+
with param.exceptions_summarized():
+    b.t = 5
+
+
+
+
+
ValueError: Range parameter 'T.t' only takes a tuple value, not <class 'int'>.
+
+
+
+
+
+
+
with param.exceptions_summarized():
+    b.t = (5,5,5)
+
+
+
+
+
ValueError: Attribute 'length' of Range parameter 'T.t' is not of the correct length (3 instead of 2).
+
+
+
+
+
+
+
with param.exceptions_summarized():
+    b.t = (5,"5")
+
+
+
+
+
ValueError: Range parameter 'T.t' only takes numeric values, not <class 'str'>.
+
+
+
+
+
+
+
with param.exceptions_summarized():
+    b.t = (-500,500)
+
+
+
+
+
ValueError: Range parameter 'T.t' lower bound must be in range [-100, None], not -500.
+
+
+
+
+
+
+
import datetime
+class D(param.Parameterized):
+    d = param.CalendarDateRange((datetime.date.fromisoformat('1900-01-01'),
+                                 datetime.date.fromisoformat('1910-12-31')))
+c = D()
+c.d
+
+
+
+
+
(datetime.date(1900, 1, 1), datetime.date(1910, 12, 31))
+
+
+
+
+
+
+
with param.exceptions_summarized():
+    c.d=(1905, 1907)
+
+
+
+
+
ValueError: CalendarDateRange parameter 'D.d' only takes date types, not (1905, 1907).
+
+
+
+
+
+
+

Lists#

+
    +
  • param.List: A Python list of objects, usually of a specified type.

  • +
  • param.HookList: A list of callable objects, for executing user-defined code at some processing stage

  • +
+

List Parameters accept a Python list of objects. Typically the item_type will be specified for those objects, so that the rest of the code does not have to further check types when it refers to those values. Where appropriate, the bounds of the list can be set as (min_length, max_length), defaulting to (0,None). Because List parameters already have an empty value ([]), they do not support allow_None.

+

A param.HookList is a list whose elements are callable objects (typically either functions or objects with a __call__ method). A HookList is intended for providing user configurability at various stages of some processing algorithm or pipeline. At present, there is no validation that the provided callable takes any particular number or type of arguments.

+
+
+
import param
+class L(param.Parameterized):
+    ls = param.List(["red","green","blue"], item_type=str, bounds=(0,10))
+
+e = L()
+e.ls
+
+
+
+
+
['red', 'green', 'blue']
+
+
+
+
+
+
+
with param.exceptions_summarized():
+    e.ls = [1,2]
+
+
+
+
+
TypeError: List parameter 'L.ls' items must be instances of <class 'str'>, not <class 'int'>.
+
+
+
+
+
+
+
with param.exceptions_summarized():
+    e.ls = [str(i) for i in range(20)]
+
+
+
+
+
ValueError: List parameter 'L.ls' length must be between 0 and 10 (inclusive), not 20.
+
+
+
+
+
+
+
class multi_stage_example(param.Parameterized):
+    before = param.HookList()
+    during = param.HookList()
+    after  = param.HookList()
+    
+    values = param.List([1.5,-8.1,6.9,100.0], item_type=float)
+    
+    def __call__(self):
+        for h in self.before: h(self)
+        s = 0
+        for v in self.values:
+            v_ = v
+            for h in self.during: v_ = h(v_)
+            s += v_
+        for h in self.after: h()
+        return s
+
+ex = multi_stage_example()
+ex()
+
+
+
+
+
100.3
+
+
+
+
+
+
+
def validate(obj):
+    for i in obj.values:
+        if i<0:
+            print("Negative value found in argument")
+
+m = multi_stage_example(before=[validate])
+
+m()
+
+
+
+
+
Negative value found in argument
+
+
+
100.3
+
+
+
+
+
+
+
from math import fabs
+
+ex.during=[abs]
+ex()
+
+
+
+
+
116.5
+
+
+
+
+
+
+

Paths#

+
    +
  • param.Path: A POSIX-style string specifying the location of a local file or folder

  • +
  • param.Filename: A POSIX-style string specifying the location of a local file

  • +
  • param.Foldername: A POSIX-style string specifying the location of a local folder

  • +
+

A Path can be set to a string specifying the path of a file or folder. In code, the string should be specified in POSIX (UNIX) style, using forward slashes / and starting from / if absolute or some other character if relative. When retrieved, the string will be in the format of the user’s operating system.

+

Relative paths are converted to absolute paths by searching for a matching filename on the filesystem in the current working directory (obtained with os.getcwd()). If search_paths is provided and not empty, the folders in that list are searched for the given filename, in order, returning the absolute path for the first match found by appending the provided path to the search path. An IOError is raised if the file or folder is not found. If search_paths is empty (the default), the file or folder is expected to be in the current working directory.

+

When check_exists is set to False (default is True) the provided path can optionally exist. This is for instance useful to declare an output file path that is meant to be created at a later stage in a process. In the default case the path must exist, on Parameter instantiation and setting.

+

Either a file or a folder name is accepted by param.Path, while param.Filename accepts only file names and param.Foldername accepts only folder names.

+
+
+
class P(param.Parameterized):
+    p = param.Path('Parameter_Types.ipynb')
+    f = param.Filename('Parameter_Types.ipynb')
+    d = param.Foldername('lib', search_paths=['/','/usr','/share'])
+    o = param.Filename('output.csv', check_exists=False)
+    
+p = P()
+p.p
+
+
+
+
+
'/home/runner/work/param/param/doc/user_guide/Parameter_Types.ipynb'
+
+
+
+
+
+
+
p.p = '/usr/lib'
+p.p
+
+
+
+
+
'/usr/lib'
+
+
+
+
+
+
+
p.f
+
+
+
+
+
'/home/runner/work/param/param/doc/user_guide/Parameter_Types.ipynb'
+
+
+
+
+
+
+
with param.exceptions_summarized():
+    p.f = '/usr/lib'
+
+
+
+
+
OSError: File '/usr/lib' not found.
+
+
+
+
+
+
+
p.d
+
+
+
+
+
'/lib'
+
+
+
+
+
+
+
with param.exceptions_summarized():
+    p.d = 'Parameter_Types.ipynb'
+
+
+
+
+
OSError: Folder Parameter_Types.ipynb was not found in the following place(s): ['/home/runner/work/param/param/doc/user_guide/Parameter_Types.ipynb'].
+
+
+
+
+
+
+
p.o  # the output file doesn't exist yet
+
+
+
+
+
'output.csv'
+
+
+
+
+
+
+
with open(p.o, 'w') as f:
+    f.write('Param is awesome!')
+
+p.o  # it now exists, getting its value resolve the full file path
+
+
+
+
+
'/home/runner/work/param/param/doc/user_guide/output.csv'
+
+
+
+
+
+
+

Selectors#

+
    +
  • param.Selector: One object selected out of a provided ordered list of objects

  • +
  • param.ListSelector: Multiple objects selected out of a provided list of objects

  • +
  • param.FileSelector: One filename selected out of those matching a provided glob

  • +
  • param.MultiFileSelector: Multiple filenames selected out of those matching a provided glob

  • +
+

The value of a Selector is one or more items from a set of allowed values. All Selector types must implement get_range(), providing a concrete list of available options for the value.

+

A param.Selector accepts a list or dictionary of objects, and has a single default (current) value that must be one of those objects. If not otherwise specified, the default will be the first item from the list or dictionary.

+

Providing the objects as a list is appropriate for selecting among a set of strings, or among a set of Parameterized objects that each have a “name” parameter. That way, a UI that lets users select by string will have a suitable string available for each object to let the user make a choice between them.

+

Otherwise, the objects should be provided as a name:value dictionary, where the string name will be stored for use in such a UI, but is not otherwise accessed by Param. The values from setting and getting the parameter are always the actual underlying object, not the string names.

+

To make it easier to modify the collection of objects, they are wrapped in a container that supports both list-style and dictionary-style methods. This approach ensures that there is a consistent API for updating the objects and that modifying the objects in place still triggers an event.

+

If the list of available objects is not meant be exhaustive, you can specify check_on_set=False (which automatically applies if the initial list is empty). Objects will then be added to the objects list whenever they are set, including as the initial default. check_on_set=False can be useful when the predefined set of objects is not exhaustive, letting a user select from the existing list for convenience while also being able to supply any other suitable object they can construct. When check_on_set=True, the initial value (and all subsequent values) must be in the objects list.

+

Because Selector is usually used to allow selection from a list of existing (instantiated) objects, instantiate is False by default, but you can specify instantiate=True if you want each copy of this Parameter value to be independent of other instances and superclasses.

+

In cases where the objects in the list cannot be known when writing the Parameterized class but can be calculated at runtime, you can supply a callable (of no arguments) to compute_default_fn, and then ensure that at runtime you call compute_default on that Parameter to initialize the value.

+

A param.ListSelector works just the same as a regular Selector, but the value is a list of valid objects from the available objects, rather than just one. Each item in the list is checked against the objects, and thus the current value is thus a subset of the objects, rather than just one of the objects.

+

A param.FileSelector works like a regular Selector with the value being a filename and the objects being computed from files on a file system. The files are specified as a path glob, and all filenames matching the glob are valid objects for the parameter.

+

A param.MultiFileSelector is the analog of ListSelector but for files, i.e., again supporting a path glob but allowing the user to select a list of filenames rather than a single filename. The default value in this case is all of the matched files, not just the first one.

+
+
+
colors = ["red","green","blue"]
+
+class S(param.Parameterized):
+    o = param.Selector(objects=colors)
+    ls = param.ListSelector(colors[0:2], objects=colors)
+    
+s = S()
+s.o
+
+
+
+
+
'red'
+
+
+
+
+
+
+
s.o = "green"
+s.o
+
+
+
+
+
'green'
+
+
+
+
+
+
+
with param.exceptions_summarized():
+    s.o = "yellow"
+
+
+
+
+
ValueError: Selector parameter 'S.o' does not accept 'yellow'; valid options include: '[red, green, blue]'
+
+
+
+
+
+
+
with param.exceptions_summarized():
+    s.o = 42
+
+
+
+
+
ValueError: Selector parameter 'S.o' does not accept 42; valid options include: '[red, green, blue]'
+
+
+
+
+
+
+
s.ls
+
+
+
+
+
['red', 'green']
+
+
+
+
+
+
+
s.ls=['blue']
+s.ls
+
+
+
+
+
['blue']
+
+
+
+
+
+
+
with param.exceptions_summarized():
+    s.ls=['red','yellow']
+    s.ls
+
+
+
+
+
ValueError: ListSelector parameter 'S.ls' does not accept 'yellow'; valid options include: '[red, green, blue]'
+
+
+
+
+
+
+
class F(param.Parameterized):
+    f = param.FileSelector(path='/usr/share/*')
+    fs = param.MultiFileSelector(path='/usr/share/*')
+    
+f = F()
+f.f
+
+
+
+
+
'/usr/share/GConf'
+
+
+
+
+
+
+
f.param.f.objects[0:3]
+
+
+
+
+
['/usr/share/GConf', '/usr/share/ImageMagick-6', '/usr/share/PackageKit']
+
+
+
+
+
+
+
f.fs = f.param.fs.objects[0:2]
+f.fs
+
+
+
+
+
['/usr/share/GConf', '/usr/share/ImageMagick-6']
+
+
+
+
+
+
+

ClassSelectors#

+
    +
  • param.ClassSelector: An instance or class of a specified Python class or superclass

  • +
  • param.Dict: A Python dictionary

  • +
  • param.Array: NumPy array

  • +
  • param.Series: A Pandas Series

  • +
  • param.DataFrame: A Pandas DataFrame

  • +
+

A ClassSelector has a value that is either an instance or a subclass of a specified Python class_. By default, requires an instance of that class, but specifying is_instance=False means that a subclass must be selected instead.

+

Like Selector types, all ClassSelector types implement get_range(), in this case providing an introspected list of all the concrete (not abstract) subclasses available for the given class. If you want a class to be treated as abstract so that it does not show up in such a list, you can have it declare __abstract=True as a class attribute. In a GUI, the range list allows a user to select a type of object they want to create, and they can then separately edit the new object’s parameters (if any) to configure it appropriately.

+
+
+
class C(param.Parameterized):
+    e_instance = param.ClassSelector(default=ZeroDivisionError("1/0"), class_=ArithmeticError)
+    e_class    = param.ClassSelector(default=ZeroDivisionError, class_=ArithmeticError, is_instance=False)
+    
+c = C(e_class=OverflowError)
+c.e_class, c.e_instance
+
+
+
+
+
(OverflowError, ZeroDivisionError('1/0'))
+
+
+
+
+
+
+
c.param.e_instance.get_range()
+
+
+
+
+
OrderedDict([('ArithmeticError', ArithmeticError),
+             ('FloatingPointError', FloatingPointError),
+             ('OverflowError', OverflowError),
+             ('ZeroDivisionError', ZeroDivisionError),
+             ('DecimalException', decimal.DecimalException),
+             ('DivisionByZero', decimal.DivisionByZero),
+             ('DivisionUndefined', decimal.DivisionUndefined),
+             ('Clamped', decimal.Clamped),
+             ('Rounded', decimal.Rounded),
+             ('Inexact', decimal.Inexact),
+             ('Subnormal', decimal.Subnormal),
+             ('FloatOperation', decimal.FloatOperation),
+             ('InvalidOperation', decimal.InvalidOperation),
+             ('Underflow', decimal.Underflow),
+             ('Overflow', decimal.Overflow),
+             ('ConversionSyntax', decimal.ConversionSyntax),
+             ('DivisionImpossible', decimal.DivisionImpossible),
+             ('InvalidContext', decimal.InvalidContext)])
+
+
+
+
+
+
+
c.param.e_class.get_range()
+
+
+
+
+
OrderedDict([('ArithmeticError', ArithmeticError),
+             ('FloatingPointError', FloatingPointError),
+             ('OverflowError', OverflowError),
+             ('ZeroDivisionError', ZeroDivisionError),
+             ('DecimalException', decimal.DecimalException),
+             ('DivisionByZero', decimal.DivisionByZero),
+             ('DivisionUndefined', decimal.DivisionUndefined),
+             ('Clamped', decimal.Clamped),
+             ('Rounded', decimal.Rounded),
+             ('Inexact', decimal.Inexact),
+             ('Subnormal', decimal.Subnormal),
+             ('FloatOperation', decimal.FloatOperation),
+             ('InvalidOperation', decimal.InvalidOperation),
+             ('Underflow', decimal.Underflow),
+             ('Overflow', decimal.Overflow),
+             ('ConversionSyntax', decimal.ConversionSyntax),
+             ('DivisionImpossible', decimal.DivisionImpossible),
+             ('InvalidContext', decimal.InvalidContext)])
+
+
+
+
+
+
+
with param.exceptions_summarized():
+    c.e_class = Exception
+
+
+
+
+
ValueError: ClassSelector parameter 'C.e_class' value must be a subclass of ArithmeticError, not <class 'Exception'>.
+
+
+
+
+
+
+
with param.exceptions_summarized():
+    c.e_instance = ArithmeticError
+
+
+
+
+
ValueError: ClassSelector parameter 'C.e_instance' value must be an instance of ArithmeticError, not <class 'ArithmeticError'>.
+
+
+
+
+
+
+
c.e_instance = ArithmeticError()
+c.e_instance
+
+
+
+
+
ArithmeticError()
+
+
+
+
+

Various types of ClassSelector are provided for specific data types:

+
    +
  • param.Dict: class_=dict, accepting a Python dictionary

  • +
  • param.Array: class=numpy.ndarray, accepting a NumPy array

  • +
  • param.Series: class_=pandas.Series, a Pandas Series. Accepts constraints on the number of rows, either as an integer length (e.g. rows=10) or a range tuple rows=(2,4)).

  • +
  • param.DataFrame: class_=pandas.DataFrame, a Pandas DataFrame. Accepts constraints on the number of rows (as for param.Series) or columns (with numerical or range values as for rows or as a list of column names (which must appear in that order) or as a set of column names (which can appear in any order)).

  • +
+
+
+
import numpy as np, pandas as pd
+
+class D(param.Parameterized):
+    d = param.Dict(dict(a=1, b="not set", c=2.0))
+    a = param.Array(np.array([1,-1]))
+    s = param.Series(pd.Series([1,-1]))
+    f = param.DataFrame(pd.DataFrame({'a':[1,2], 'b':[2,3], 'c':[4,5]}), rows=(2,None), columns=set(['a','b']))
+
+d = D()
+d.d = {5:np.nan}
+d.d
+
+
+
+
+
{5: nan}
+
+
+
+
+
+
+
with param.exceptions_summarized():
+    d.d=[("a",1)]
+
+
+
+
+
ValueError: Dict parameter 'D.d' value must be an instance of dict, not [('a', 1)].
+
+
+
+
+
+
+
df = pd.DataFrame({'b':[-2,-3], 'a':[-1,-2]})
+d.f = df
+d.f
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + +
ba
0-2-1
1-3-2
+
+
+
+
+
with param.exceptions_summarized():
+    df = pd.DataFrame({'a':[-2,-3], 'c':[-1,-2]})
+    d.f = df
+
+
+
+
+
ValueError: DataFrame parameter 'D.f': provided columns ['a', 'c'] does not contain required columns ['a', 'b']
+
+
+
+
+
+
+
with param.exceptions_summarized():
+    df = pd.DataFrame({'a':[-2], 'b':[-1]})
+    d.f = df
+
+
+
+
+
ValueError: DataFrame parameter 'D.f': row length 1 does not match declared bounds of (2, None)
+
+
+
+
+
+

classlist and param.descendents#

+

If you are building a GUI or some other mechanism allowing the user to choose a class or an instance of a specified class in a ClassSelector, you may want to construct a list of all subclasses or superclasses of the given class. To make it easy to traverse upwards or downwards in the inheritance hierarchy in this way, param provides the classlist and param.descendents functions. classlist provides a list of the superclasses of the provided object, including itself, in order from least to most specific:

+
+
+
from param.parameterized import classlist
+
+classlist(D)
+
+
+
+
+
(object, param.parameterized.Parameterized, __main__.D)
+
+
+
+
+

As you can see, D is a type of Parameterized, and a Parameterized is a type of Python object. Conversely (and typically more usefully), param.descendents provides a list of the subclasses of the provided object, including itself:

+
+
+
param.descendents(param.SelectorBase)
+
+
+
+
+
[param.SelectorBase,
+ param.Selector,
+ param.ClassSelector,
+ param.ObjectSelector,
+ param.FileSelector,
+ param.ListSelector,
+ param.Dict,
+ param.Array,
+ param.DataFrame,
+ param.Series,
+ param.MultiFileSelector]
+
+
+
+
+

As you can see, there are many subtypes of SelectorBase. This list is calculated from whatever subtypes are currently defined in this Python session. If you derive an additional subtype or load code that defines an additional subtype, this list will get longer, so you need to make sure that all such code has been executed before letting the user make a selection of a subtype.

+
+
+
+

Invocations#

+
    +
  • param.Callable: A callable object, such as a function

  • +
  • param.Action: A callable with no arguments, ready to invoke

  • +
  • param.Event: Empty action, for use in triggering events for watchers

  • +
  • param.Composite: Wrapper around other parameters, letting them be set as a tuple

  • +
+

Invocation parameters are a loose group of types that either contain an executable (callable) object, are invoked to execute some other code, or are set to change the value of some other parameter(s) or attribute(s).

+

A Callable may be set to any callable object, typically either a function or else an instance of a class that provides a __call__ method. At present, there is no validation that the provided callable takes any particular number or type of arguments. Lambdas can be provided, but note that the resulting parameter value will no longer be picklable, so if you need to use pickling (setstate and getstate), be sure to use a named function instead.

+

An Action is the same as a Callable, but is expected to have no arguments. In a GUI an Action is typically mapped to a button whose name or label is the name of this parameter.

+

An Event Parameter has a Boolean value but is primarily intended for triggering events on its watchers. See Dependencies and Watchers for the details.

+

A Composite Parameter has a value that is looked up from the value of a list of attributes of this class (which may or may not be parameters) and that when set changes the values of those other attributes or parameters. This type of Parameter can be useful for treating a set of related values as a group for setting purposes, but as individual parameters for code that reads from them. As of Param 1.10, Composite parameters have not been tested with watchers and dependencies and may not behave appropriately for such uses.

+
+
+
def identity(x): return x
+    
+def print_time_of_day():
+    print(datetime.date.today())
+
+class A(param.Parameterized):
+    transformer = param.Callable(identity)
+    a = param.Action(print_time_of_day)
+    
+    def __call__(self, x):
+        return self.transformer(x)
+ 
+a = A()
+a(5)
+
+
+
+
+
5
+
+
+
+
+
+
+
def double(x):
+    return 2*x
+    
+d = A(transformer=double)
+d(5)
+
+
+
+
+
10
+
+
+
+
+
+
+
d.a()
+
+
+
+
+
2023-09-25
+
+
+
+
+
+
+
with param.exceptions_summarized():
+    d.a = 5
+
+
+
+
+
ValueError: Action parameter 'A.a' only takes a callable object, not objects of <class 'int'>.
+
+
+
+
+
+
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/user_guide/ParameterizedFunctions.html b/user_guide/ParameterizedFunctions.html new file mode 100644 index 0000000..10482a0 --- /dev/null +++ b/user_guide/ParameterizedFunctions.html @@ -0,0 +1,774 @@ + + + + + + + + + + + + ParameterizedFunctions — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

ParameterizedFunctions#

+

Parameterized classes and objects are full-featured substitues for Python objects, providing rich support and control for how attributes behave. What if you need similar features, but for functions rather than objects?

+

Python functions don’t directly support the various language features like descriptors that Param builds on, but you can instead make a Python class or object that behaves like a function, while still supporting Parameters. To make that easier, Param provides an abstract class ParameterizedFunction that you can use as a superclass for any function-like object you want to write. A ParameterizedFunction automatically invokes its __call__ method whenever it is instantiated. So, all you need to do is implement the __call__ method with the implementation of your function. For example:

+
+
+
from param import Parameter, ParameterizedFunction, ParamOverrides
+
+class multiply(ParameterizedFunction):
+    "Function to multiply two arguments."
+
+    left  = Parameter(2, doc="Left-hand-side argument")
+    right = Parameter(4, doc="Right-hand-side argument")
+
+    def __call__(self, **params):
+        p = ParamOverrides(self, params)
+        return p.left * p.right
+    
+multiply()
+
+
+
+
+
8
+
+
+
+
+
+
+
multiply(left=3, right=7)
+
+
+
+
+
21
+
+
+
+
+
+
+
multiply.left = 7
+multiply(right = 10)
+
+
+
+
+
70
+
+
+
+
+

Here you can see that multiply acts like any other function that takes keyword arguments, but the arguments are now documented, potentially type checked, and have default values.

+

This implementation depends on the separate object param.ParamOverrides, which provides two-level lookup of parameter values: first on the arguments provided to the call, and then (if not provided) on the ParameterizedFunction instance. This way a user can choose to provide any or none of the arguments when the function (really, function object) is invoked.

+

The __call__ method can also take positional arguments, but in that case the class author would need to handle any mapping from those arguments to parameters there might be. __call__ can also take extra keyword arguments beyond parameter values, but if so, you’ll need to construct ParamOverrides as p = ParamOverrides(self, params, allow_extra_keywords=True), then access the extra (non-Parameter) keywords in p.extra_keywords and process those explicitly.

+
+

.instance()#

+

Usually, with a Parameterized object, you can modify values on the instance level, in addition to the class level shown above. Here, however, there is no instance to grab, because the ParameterizedFunction is called and evaluated, returning a value rather than the function object. If you want to grab an instance where you can set a value and then call the instance, you can use the .instance() method of a ParameterizedFunction:

+
+
+
multiply_by_10 = multiply.instance(right=10)
+multiply_by_10(left=8)
+
+
+
+
+
80
+
+
+
+
+
+
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/user_guide/Parameters.html b/user_guide/Parameters.html new file mode 100644 index 0000000..fb1628a --- /dev/null +++ b/user_guide/Parameters.html @@ -0,0 +1,2033 @@ + + + + + + + + + + + + Parameters and Parameterized objects — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

Parameters and Parameterized objects#

+

Fundamentally, what Param does is allow you to control how certain user-visible attributes (“parameters”) of a Python class or instance will behave when their value is get or set. A user of that class can set those attributes to control the class, but only if the mechanisms provided by Param and configured by the programmer allow it. In this way, Param allows the author of a class to implement and constrain what a user can do with that class or an instance of it, setting up a clear contract of what is and is not allowed, and how that attribute will behave. To do this, Param provides two main new types of Python object: Parameter objects, and Parameterized objects.

+

A parameter is a special kind of Python class attribute. Setting a Parameterized class attribute to be a Parameter instance causes that attribute of the class (and the class’s instances) to be treated as a parameter, not just an ordinary attribute. Parameters support special behavior, including dynamically generated parameter values, documentation strings, constant and read-only parameters, type or range checking at assignment time, and values dependent on those of other parameters.

+

More concretely, a Python Parameter object inherits from param.Parameter and stores various metadata attributes describing how a corresponding Python attribute of a Parameterized object should behave. By convention, we will use a capital ‘P’ Parameter to refer to the Parameter object itself, and a lower-case ‘p’ parameter to refer to the Python attribute it controls (i.e., the Parameter’s “value”).

+

A Parameterized class is a Python class that inherits from param.Parameterized and can accept Parameter objects as class attributes. A Parameterized class or instance uses the Parameter objects to determine how the corresponding attribute should behave.

+

There are many specific types of Parameter with different behavior, discussed in Parameter Types, but here we will cover the common behavior between all Parameter types when used in a Parameterized object.

+
+

Parameter metadata#

+

Each Parameter type can define additional behavior and associated metadata, but the metadata supported for all Parameter types includes:

+
    +
  • default: Default value for this parameter at the class level, which will also be the value at the Parameterized instance level if it hasn’t been set separately on the instance.

  • +
  • name: String name of this parameter, which is typically determined by the attribute name of this Parameter in the owning Parameterized object, and is not set directly by a programmer.

  • +
  • label: Optional long name used for a verbose listing; defaults to the name.

  • +
  • allow_None: Whether this parameter accepts None as an allowed value, in addition to whatever other types it accepts. Automatically set to True if the default value of this Parameter is None.

  • +
  • doc: Docstring describing this parameter, which can be used by automatic documentation systems.

  • +
  • constant: Parameter whose value can only be changed at the class level or in a Parameterized constructor. Once the Parameterized instance has been created, the value is constant except in the context of with param.edit_constant(obj) (see below).

  • +
  • readonly: Parameter whose value cannot be set by a user either on an instance or at the class level. Can still be changed inside a codebase by temporarily overriding this value, e.g. to report internal state.

  • +
  • instantiate: Whether to deepcopy the default value into a Parameterized instance when it is created. False by default for Parameter and most of its subtypes, but some Parameter types commonly used with mutable containers default to instantiate=True to avoid interaction between separate Parameterized instances, and users can control this when declaring the Parameter (see below).

  • +
  • per_instance: whether a separate Parameter instance will be created for every Parameterized instance created. Similar to instantiate, but applies to the Parameter object rather than to its value.

  • +
  • precedence: Optional numeric value controlling whether this parameter is visible in a listing and if so in what order.

  • +
+

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:

+
+
+
import param
+from param import Parameter, Parameterized
+
+p = Parameter(default=42, doc="The answer", constant=True)
+p.default
+
+
+
+
+
42
+
+
+
+
+
+
+
p.allow_None
+
+
+
+
+
False
+
+
+
+
+
+
+
p.doc
+
+
+
+
+
'The answer'
+
+
+
+
+
+
+

Parameter objects and instances#

+

In most cases, a Parameter will not be declared on its own as above; the Parameter object by itself is little more than a container for the metadata above. Until it is put into a class, most of those declarations are not meaningful, because what the Parameter object does is to specify how the corresponding Python attribute of that class should be handled. For example, we can define a Parameterized class with a couple of Parameter objects, and we’ll then be able to access the corresponding attributes of that class:

+
+
+
class A(Parameterized):
+    question = Parameter("What is it?", doc="The question")
+    answer = Parameter(default=2, constant=True, doc="The answer")
+    ultimate_answer = Parameter(default=42, readonly=True, doc="The real answer")
+
+a = A(question="How is it?", answer="6")
+
+
+
+
+

Here, we created a Parameterized class A, with parameters question and answer, each with default values. We then instantiated a Python object a of type A. Without having to write a constructor for A, we were able to provide our own values for question and answer, while inheriting the default value of ultimate_answer. This approach gives a lot of (but not too much!) configurability to the user of this class, without much effort by the class author. Any values we provide at instantiation need to be allowed by the Parameter declaration; e.g. here we could not provide a value for ultimate_answer when declaring a, because that parameter is declared read only:

+
+
+
with param.exceptions_summarized():
+    A(ultimate_answer="no")
+
+
+
+
+
TypeError: Read-only parameter 'ultimate_answer' cannot be modified
+
+
+
+
+

Now that we have a Parameterized instance a, we can access the attributes we defined just as if they were normal Python instance attributes, and we’ll get the values we provided:

+
+
+
a.question
+
+
+
+
+
'How is it?'
+
+
+
+
+
+
+
a.answer
+
+
+
+
+
'6'
+
+
+
+
+

Meanwhile, the Parameterized class A (not the instance a) still has the default values, accessible as class attributes and used for any future objects instantiated of type A:

+
+
+
A.question
+
+
+
+
+
'What is it?'
+
+
+
+
+
+
+
A.answer
+
+
+
+
+
2
+
+
+
+
+
+
+
b = A()
+b.answer
+
+
+
+
+
2
+
+
+
+
+

If accessing the attribute always gives us a value whether on the instance or the class, what happened to the Parameter objects? They are stored on the Parameterized instance or class, and are accessible via a special param accessor object at either the instance or class levels, via attribute or key:

+
+
+
a.param['question']
+
+
+
+
+
<param.parameterized.Parameter at 0x7f54accc3180>
+
+
+
+
+
+
+
a.param.question
+
+
+
+
+
<param.parameterized.Parameter at 0x7f54accc3180>
+
+
+
+
+
+
+
a.param.question.name
+
+
+
+
+
'question'
+
+
+
+
+
+
+
a.param.question.default
+
+
+
+
+
'What is it?'
+
+
+
+
+
+
+
A.param.question.default
+
+
+
+
+
'What is it?'
+
+
+
+
+

Once the Parameterized instance is created, the attributes can continue to be modified on it as often as you like, as long as the value is allowed by the Parameter object involved. E.g. question can still be changed, while answer is constant and cannot be changed after the Parameterized object has been instantiated:

+
+
+
with param.exceptions_summarized():
+    a.question = True
+    a.answer = 5
+
+
+
+
+
TypeError: Constant parameter 'answer' cannot be modified
+
+
+
+
+
+
+
a.question
+
+
+
+
+
True
+
+
+
+
+

Note that if for some reason you do need to change the value of a constant parameter (typically inside of your Parameterized object’s own code), you can do so using the param.edit_constant context manager:

+
+
+
with param.edit_constant(a):
+    a.answer = 30
+a.answer
+
+
+
+
+
30
+
+
+
+
+

In most cases, the only time you need to worry about the difference between a Parameter and a regular Python attribute is when you first declare it; after that it will sit there happily behaving as instructed, noticeable only when a user attempts something the declarer of that Parameter has not allowed. You can safely leave the various metadata items at their defaults most of the time, but they are all there for when your particular application requires a certain behavior.

+
+
+

Parameter inheritance#

+

Parameter objects and their metadata are inherited in a hierarchy of Parameterized objects. Let’s see how that works:

+
+
+
class A(Parameterized):
+    question = Parameter("What is it?", doc="The question")
+    answer = Parameter(default=2, constant=True, doc="The answer")
+    ultimate_answer = Parameter(default=42, readonly=True, doc="The real answer")
+
+class B(A):
+    ultimate_answer = Parameter(default=84)
+
+b = B()
+b.question
+
+
+
+
+
'What is it?'
+
+
+
+
+
+
+
A.question = "How are you?"
+
+
+
+
+
+
+
b.question
+
+
+
+
+
'How are you?'
+
+
+
+
+

Here you can see that B inherits question from A, and as long as question has not been set explicitly on b, b.question will report the value from where that Parameter was defined, i.e. A in this case. If question is subsequently set on b, b.question will no longer be affected by the value in A:

+
+
+
b.question = "Why?"
+A.question = "Who?"
+b.question
+
+
+
+
+
'Why?'
+
+
+
+
+

As you can see, parameters not specified in B are still fully usable in it, if they were declared in a superclass. Metadata associated with that parameter is also inherited, if not explicitly overidden in B.

+
+
+
b.param.ultimate_answer.constant
+
+
+
+
+
False
+
+
+
+
+
+
+
b.param.ultimate_answer.readonly
+
+
+
+
+
True
+
+
+
+
+
+
+
b.ultimate_answer
+
+
+
+
+
84
+
+
+
+
+
+
+
b.param.ultimate_answer.default
+
+
+
+
+
84
+
+
+
+
+
+
+
b.param.ultimate_answer.doc
+
+
+
+
+
'The real answer'
+
+
+
+
+

Looking at the metadata values of ultimate_answer on b or B you can see that:

+
    +
  • All the default metadata values like constant, allow_none, …, were inherited from the base Parameter object provided by Param

  • +
  • The read_only and doc metadata values were inherited from A

  • +
  • The default metadata value of ultimate_answer in B overrode the value provided in A.

  • +
+

Parameter inheritance like this lets you (a) use a parameter in many subclasses without having to define it more than once, and (b) control the value of that parameter conveniently across the entire set of subclasses and instances, as long as that attribute has not been set on those objects already. Using inheritance in this way is a very convenient mechanism for setting default values and other “global” parameters, whether before a program starts executing or during it.

+

help(b) or help(B) will list all parameters. You can also prefix or suffix a Parameterized object with ? in an IPython console/Notebook to display the help:

+
+
+
B?
+
+
+
+
+

Param help

+
+
+

Parameter value instantiation#

+

So much of the parameter metadata is there to help you control whether and how the parameter value is instantiated on Parameterized objects as they are created or new Parameterized subclasses as they are defined. Depending on how you want to use that Parameter and what values it might take, controlling instantiation can be very important when mutable values are involved. While the default behavior shown above is appropriate for immutable attributes, what happens if the value (unlike Python strings) is mutable? Things get a lot more complex.

+
+
+
s = [1, 2, 3]
+
+class C(Parameterized):
+    s1 = Parameter(s, doc="A sequence")
+    s2 = Parameter(s, doc="Another sequence")
+
+c = C()
+
+
+
+
+

Here, both parameters s1 and s2, on both A and B effectively point to the same underlying sequence s:

+
+
+
c.s1 is c.s2
+
+
+
+
+
True
+
+
+
+
+
+
+
s[1] *= 5
+
+
+
+
+
+
+
s
+
+
+
+
+
[1, 10, 3]
+
+
+
+
+
+
+
c.s1
+
+
+
+
+
[1, 10, 3]
+
+
+
+
+
+
+
c.s1[2] = 'a'
+
+
+
+
+
+
+
c.s1
+
+
+
+
+
[1, 10, 'a']
+
+
+
+
+
+
+
c.s2
+
+
+
+
+
[1, 10, 'a']
+
+
+
+
+

As you can see, there is only one actual sequence here, and s, s1, and s2 all point to it. In some cases such behavior is desirable, e.g. if the mutable object is a specific global list (e.g. a set of search paths) with a unique identity and all of the parameters are meant to point to that specific item. In other cases, it’s the contents of the mutable item that are important, and no sharing of contents is intended. Luckily, Param supports that case as well, if you provide instantiate=True (default is False):

+
+
+
s = [1,2,3]
+
+class D(Parameterized):
+    s1 = Parameter(default=s, doc="A sequence", instantiate=True)
+    s2 = Parameter(default=s, doc="Another sequence", instantiate=True)
+
+d = D()
+
+
+
+
+

Now, parameters s1 and s2 point to their own copies of the sequence, independent of each other and of the original argument s:

+
+
+
d.s1 is d.s2
+
+
+
+
+
False
+
+
+
+
+
+
+
s *= 2
+
+
+
+
+
+
+
s
+
+
+
+
+
[1, 2, 3, 1, 2, 3]
+
+
+
+
+
+
+
d.s1
+
+
+
+
+
[1, 2, 3]
+
+
+
+
+
+
+
d.s1[2] = 'a'
+
+
+
+
+
+
+
d.s2
+
+
+
+
+
[1, 2, 3]
+
+
+
+
+

Of course, copying the data into each instance like that costs memory, and moreover prevents controlling all instances at once by setting a class attribute as we saw earlier, which is why instantiate is not True by default. As a rule of thumb, set instantiate=True if and only if (a) your Parameter can take mutable values, and (b) you want those values to be independent between Parameterized instances.

+
+
+

Parameter object instantiation#

+

instantiate controls how parameter values behave, but similar issues arise for Parameter objects, which offer similar control via the per_instance metadata declaration. per_instance (True by default) provides a logically distinct Parameter object for every Parameterized instance, allowing each such instance to have different metadata for that parameter. For example, we can set the label separately for each instance without clobbering each other:

+
+
+
d1 = D()
+d2 = D()
+d1.param.s1.label = "sequence 1"
+d2.param.s1.label = "(sequence 1)"
+d2.param.s1.label
+
+
+
+
+
'(sequence 1)'
+
+
+
+
+
+
+
d1.param.s1.label
+
+
+
+
+
'sequence 1'
+
+
+
+
+

This capability is useful for situations with dynamically updated metadata, e.g. if you need setting one parameter’s value (e.g. ‘Continent’) to change the allowed values of another parameter (e.g. ‘Country’). The underlying Parameter objects are copied lazily (only when actually changed), so that objects are not actually multiplied unless necessary. If you do want parameters to share a single Parameter object so that you can control its behavior globally, you can achieve that with per_instance=False, though the effects can be confusing in the same way as instantiate=True for mutable objects (above):

+
+
+
class E(Parameterized):
+    a = Parameter(default=3.14, label="pi", per_instance=False)
+
+e1 = E()
+e2 = E()
+e2.param.a.label = "Pie"
+e1.param.a.label
+
+
+
+
+
'Pie'
+
+
+
+
+
+
+

Instantiating with shared parameters#

+

When creating a large collection of Parameterized objects of the same type, the overhead of having separate parameters for each object can be significant. If you want, you can create the objects to share parameter values for efficiency, and also so that you can easily change a value on all such objects at the same time.

+

As an example, let’s say you’ve defined a Parameter value to be independent, such that changing one instance’s value will not affect the others:

+
+
+
class S(param.Parameterized):
+    l = Parameter(default=[1,2,3], instantiate=True)
+
+ss = [S() for i in range(10)]
+ss[0].l[2] = 5
+ss[1].l
+
+
+
+
+
[1, 2, 3]
+
+
+
+
+

Here changing the value of l on ss[0] doesn’t affect ss[1] or any other instances.

+

What if you as a user of this class are creating a very large number of similar objects and actually do want them to share the same parameter value, either to save memory or to make it easy to change all of their values at once? In that case you can use the context manager shared_parameters, and any Parameterized objects created within that context will share parameter values, such that changing one of them will affect all of them:

+
+
+
with param.shared_parameters():
+    ps = [S() for i in range(10)]
+    
+ps[0].l[2] = 5
+ps[1].l
+
+
+
+
+
[1, 2, 5]
+
+
+
+
+

This approach can provide significant speedup and memory savings in certain cases, but should only be used for good reasons, since it can cause confusion for any code expecting instances to be independent as they have been declared.

+
+
+

Displaying Parameterized objects#

+

Most of the important behavior of Parameterized is to do with instantiation, getting, and setting, as described above. Parameterized also provides a few public methods for creating string representations of the Parameterized object and its parameters:

+
    +
  • Parameterized.__str__(): A concise, non-executable representation of the name and class of this object

  • +
  • Parameterized.__repr__(): A representation of this object and its parameter values as if it were Python code calling the constructor (classname(parameter1=x,parameter2=y,...))

  • +
  • Parameterize.param._repr_html_(): A rich HTML representation of the object with its parameters listed in a table together with their metadata.

  • +
  • Parameterized.param.pprint(): Customizable, hierarchical pretty-printed representation of this Parameterized and (recursively) any of its parameters that are Parameterized objects. See Serialization and Persistence for details on customizing pprint.

  • +
+
+
+
import param
+
+class Q(param.Parameterized):
+    a = param.Number(default=39, bounds=(0,50), doc='Number a')
+    b = param.String(default="str", doc='A string')
+
+class P(Q):
+    c = param.ClassSelector(default=Q(), class_=Q, doc='An instance of Q')
+    e = param.ClassSelector(default=param.Parameterized(), class_=param.Parameterized, doc='A Parameterized instance')
+    f = param.Range(default=(0,1), doc='A range')
+
+p = P(f=(2,3), c=P(f=(42,43)), name="demo")
+
+
+
+
+
+
+
p.__str__()
+
+
+
+
+
'<P demo>'
+
+
+
+
+
+
+
p.__repr__()
+
+
+
+
+
"P(a=39, b='str', c=P(a=39, b='str', c=Q(a=39, b='str', name='Q00034'), e=Parameterized(name='Parameterized00035'), f=(42, 43), name='P00033'), e=Parameterized(name='Parameterized00038'), f=(2, 3), name='demo')"
+
+
+
+
+

The HTML representation of a Parameterized instance or class is displayed when you call <obj>.param in a Notebook.

+
+
+
p.param
+
+
+
+
+
+
+ + P() + +
+ + + + + + + + + +
NameValueTypeRange

a

39 Number >=0, <=50

b

'str' String

c

+
+ + P() + +
+ + + + + + + + + +
NameValueTypeRange

a

39 Number >=0, <=50

b

'str' String

c

+
+ + Q() + +
+ + + + + + +
NameValueTypeRange

a

39 Number >=0, <=50

b

'str' String

name

'Q00034' String nullable constant
+
+
+
ClassSelector Q

e

+
+ + Parameterized() + +
+ + + + +
NameValueTypeRange

name

'Parameterized00035' String nullable constant
+
+
+
ClassSelector Parameterized

f

(42, 43) Range

name

'P00033' String nullable constant
+
+
+
ClassSelector Q

e

+
+ + Parameterized() + +
+ + + + +
NameValueTypeRange

name

'Parameterized00038' String nullable constant
+
+
+
ClassSelector Parameterized

f

(2, 3) Range

name

'demo' String nullable constant
+
+
+
+
+
+
+
P.param
+
+
+
+
+
+
+ + P + +
+ + + + + + + + + +
NameDefaultTypeRange

a

39 Number >=0, <=50

b

'str' String

c

+
+ + Q() + +
+ + + + + + +
NameValueTypeRange

a

39 Number >=0, <=50

b

'str' String

name

'Q00031' String nullable constant
+
+
+
ClassSelector Q

e

+
+ + Parameterized() + +
+ + + + +
NameValueTypeRange

name

'Parameterized00032' String nullable constant
+
+
+
ClassSelector Parameterized

f

(0, 1) Range

name

'P' String nullable constant
+
+
+
+
+
+
+
p.param.pprint(separator="\n")
+
+
+
+
+
"P(c=P(c=Q(),     e=Parameterized(),     f=(42,43)),\n e=Parameterized(),\n f=(2,3),\n name='demo')"
+
+
+
+
+

Notice that in the case of a circular reference (p.c = P(c=p)) the representation will show an ellipsis (...) rather than recursively printing the subobject:

+
+
+
p.c=P(c=p)
+p.param.pprint()
+
+
+
+
+
"P(c=P(c=...,     e=Parameterized()), e=Parameterized(), f=(2,3), name='demo')"
+
+
+
+
+
+
+

Parameterized namespace#

+

Param allows you to create Parameterized objects by inheriting from the Parameterized base class. Param has evolved over time to reduce its footprint and reserve as few as possible attributes on this namespace, to reduce the risk of name clashes and allow you to freely define your attribute names. Param reserves a few names that are described below, make sure not to override, unless it is stated it is allowed:

+
    +
  • Public attributes:

    +
      +
    • name: Parameterized classes and instances have a name String Parameter, that by default is set to the class name when accessed from the class and to the class name appended with a 5 digit when accessed from the instance. You can override this Parameter by your own String Parameter if you need to.

    • +
    • param: Property that helps keep the Parameterized namespace clean and disambiguate between Parameter objects and parameter values, it gives access to a namespace that offers various methods (see the section below) to update and inspect the Parameterized object at hand.

    • +
    +
  • +
  • Private attributes:

    +
      +
    • _param__parameters: Store the object returned by .param on the class

    • +
    • _param__private: Store various internal data on Parameterized class and instances

    • +
    • _param_watchers (deprecated in Param 2.0 and to be removed soon): Store a dictionary of instance watchers

    • +
    +
  • +
+
+
+
class P(param.Parameterized):
+    a = param.Number()
+    b = param.String()
+
+p = P()
+print(f'{P.name=}, {p.name=}')
+
+
+
+
+
P.name='P', p.name='P00042'
+
+
+
+
+
+
+
def namespace(obj):
+    return [o for o in dir(obj) if not o.startswith('__')]
+
+
+
+
+
+
+
namespace(P)
+
+
+
+
+
['_param__parameters',
+ '_param__private',
+ '_param_watchers',
+ 'a',
+ 'b',
+ 'name',
+ 'param']
+
+
+
+
+
+
+
namespace(p)
+
+
+
+
+
['_param__parameters',
+ '_param__private',
+ '_param_watchers',
+ 'a',
+ 'b',
+ 'name',
+ 'param']
+
+
+
+
+
+
+

Other Parameterized methods#

+

Like .param.pprint, the remaining “utility” or convenience methods available for a Parameterized class or object are provided via the .param subobject:

+
    +
  • .param.update(**kwargs): Set parameter values from the given param=value keyword arguments (or a dict or iterable), delaying watching and dependency handling until all have been updated. .param.update can also be used as a context manager to temporarily set values, that are restored to their original values when the context manager exits.

  • +
+
+
+
p.param.update(a=0, b='start');
+print(p.a, p.b)
+
+
+
+
+
0 start
+
+
+
+
+
+
+
with p.param.update(a=1, b='temp'):
+    print(f'In the context manager: {p.a=}, {p.b=}')
+print(f'After the context manager exits: {p.a=}, {p.b=}')
+
+
+
+
+
In the context manager: p.a=1, p.b='temp'
+After the context manager exits: p.a=0, p.b='start'
+
+
+
+
+
    +
  • .param.values(onlychanged=False): A dict of name,value pairs for all parameters of this object

  • +
+
+
+
p.param.values()
+
+
+
+
+
{'a': 0, 'b': 'start', 'name': 'P00042'}
+
+
+
+
+
    +
  • .param.objects(instance=True): Parameter objects of this instance or class

  • +
+
+
+
p.param.objects()
+
+
+
+
+
{'name': <param.parameterized.String at 0x7f54a49f8b80>,
+ 'a': <param.Number at 0x7f54a4f15940>,
+ 'b': <param.parameterized.String at 0x7f54a49f8cc0>}
+
+
+
+
+
    +
  • .param.add_parameter(param_name,param_obj): Dynamically add a new Parameter to this object’s class

  • +
  • .param.get_value_generator(name): Returns the underlying value-generating callable for this parameter, or the underlying static value if none

  • +
  • .param.force_new_dynamic_value(name): For a Dynamic parameter, generate a new value and return it

  • +
  • .param.inspect_value(name): For a Dynamic parameter, return the current value of the named attribute without modifying it.

  • +
+
+
+

Specialized Parameter types#

+

As you can see above, a Parameter provides a lot of power already on its own, but in practice you will want to use much more specific parameter types that reject invalid inputs and keep your code clean and simple. A specialized Parameter acts as a “contract” with the users of the code you write, declaring and defending precisely what configuration is allowed and how to achieve it. If you need to accept specific inputs like that but don’t add an appropriate Parameter type, you’ll be stuck adding exceptions and validation code throughout your codebase, whereas anything you can express at the Parameter level will be enforced automatically without any further checks or code.

+

For instance, what if you want to accept a numeric parameter, but (for some reason) can only accept numbers that are even integers? You’ll need a custom Parameter class to express a restriction like that. In this case you can do it by overriding the _validate_value method of the Parameter class:

+
+
+
import numbers
+
+class EvenInteger(param.Parameter):
+    """Integer Parameter that must be even"""
+
+    def _validate_value(self, val, allow_None):
+        super()._validate_value(val, allow_None)
+        if not isinstance(val, numbers.Number):
+            raise ValueError(
+                f"EvenInteger parameter {self.name!r} must be a number, not {val!r}."
+            )
+        
+        if not (val % 2 == 0):
+            raise ValueError(
+                f"EvenInteger parameter {self.name!r} must be even, not {val!r}."
+            )
+
+class P(param.Parameterized):
+    n = param.Number()
+    b = EvenInteger()
+    
+p=P()
+P(n=5, b=4)
+P(b=4, n=5, name='P00003')
+
+
+
+
+
P(b=4, n=5, name='P00003')
+
+
+
+
+
+
+
with param.exceptions_summarized():
+    P(n=5, b="four")
+
+
+
+
+
ValueError: EvenInteger parameter 'b' must be a number, not 'four'.
+
+
+
+
+
+
+
with param.exceptions_summarized():
+    P(n=5, b=5)
+
+
+
+
+
ValueError: EvenInteger parameter 'b' must be even, not 5.
+
+
+
+
+

Luckily, you don’t often need to write a custom Parameter class like this, because the most common cases are already provided in Param, as listed in the Parameter Types manual. If you need something more specific than the existing types, start with the one that comes closest to restricting its value to the desired set of values without excluding any allowable values. In this case all integer powers of 2 are also integers, so you’d start with param.Integer rather than param.Parameterized as above. You can then make a new subclass and add validation as above to further restrict the values to precisely what you allow. Here if you inherited from param.Integer you would no longer need to check if the input is a number, as param.Integer already does that as long as you call super as above. Your custom type can override any aspects of the Parameter if needed, e.g. to accept different items in the constructor, store additional data, add additional constraints, and so on. The existing Parameter types in param/__init__.py act as a rich source of examples for you to start with and crib from.

+
+
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/user_guide/Reactive_Expressions.html b/user_guide/Reactive_Expressions.html new file mode 100644 index 0000000..b8ca69c --- /dev/null +++ b/user_guide/Reactive_Expressions.html @@ -0,0 +1,1792 @@ + + + + + + + + + + + + Reactive Functions & Expressions — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

Reactive Functions & Expressions#

+

In the Dependencies and Watchers guide we discovered how to express dependencies and write callback functions that are invoked when parameter values change. This low-level, imperative style of expressing dynamic behavior is powerful, and works well for capturing complex behaviors in self-contained Parameterized classes with methods and Parameters. But even if you are not primarily designing a hierarchy of classes, it is still useful to be able to express dependencies between values and computations. Param 2.0 introduces a new set of declarative dynamic computation primitives that are useful even for single expressions, letting you write simple reactive functions and expressions that are re-evaluated automatically when required.

+

The reactive programming model is one you might be familiar with from spreadsheets like Excel, where formulas can reference cells or ranges and dynamically (or more precisely, reactively) recompute when the inputs to a formula changes. In Param, Parameter objects correspond to a spreadsheet cell formula’s inputs or references, and reactive expressions correspond to the formula itself. param.bind also allows the creation of a reactive function with arbitrary inputs.

+

This user guide is structured as two main sections:

+
    +
  • Reactive Functions: Using param.bind to declare functions that react when their inputs change.

  • +
  • Reactive Expressions: Using param.rx (or .rx() on Parameter objects) to wrap ordinary objects and/or parameters in a proxy that acts like the underlying object but reacts when an input changes.

  • +
+
+
+

Getting started#

+

Before we dive in to discover how this works behind the scenes, let’s get started with a concrete example. What reactive expressions are great for is writing pipelines of operations in a natural form, i.e., without having to explicitly track and update state or the control flow. In most cases, you can simply write the same non-reactive Python code you always write, but then use arguments and option values that are reactive, so that the pipeline will re-run if the value changes.

+

For an example, let’s load some data into a Pandas DataFrame and make it reactive:

+
+
+
import pandas as pd
+import param
+import param.ipython
+
+from param import rx
+
+
+
+
+
+
+
URL = 'https://datasets.holoviz.org/penguins/v1/penguins.csv'
+df = rx(pd.read_csv(URL))
+df.head(2)
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
speciesislandbill_length_mmbill_depth_mmflipper_length_mmbody_mass_gsexyear
0AdelieTorgersen39.118.7181.03750.0male2007
1AdelieTorgersen39.517.4186.03800.0female2007
+
+
+

Here, this is just the same code you’d normally use to make a DataFrame, apart from using rx() to make the DataFrame into a reactive expression. As you can see, the reactive DataFrame works like any other DataFrame, using .head() and any other DataFrame methods as usual. But now, let’s make the fixed number 2 above into a reactive expression, and see what happens:

+
+
+
nrows = rx(2)
+df.head(nrows)
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
speciesislandbill_length_mmbill_depth_mmflipper_length_mmbody_mass_gsexyear
0AdelieTorgersen39.118.7181.03750.0male2007
1AdelieTorgersen39.517.4186.03800.0female2007
2AdelieTorgersen40.318.0195.03250.0female2007
3AdelieTorgersenNaNNaNNaNNaNNaN2007
4AdelieTorgersen36.719.3193.03450.0female2007
5AdelieTorgersen39.320.6190.03650.0male2007
6AdelieTorgersen38.917.8181.03625.0female2007
7AdelieTorgersen39.219.6195.04675.0male2007
8AdelieTorgersen34.118.1193.03475.0NaN2007
9AdelieTorgersen42.020.2190.04250.0NaN2007
+
+
+

So far, nothing’s changed. But what if we change the value of nrows?

+
+
+
nrows.rx.set_input(4);
+
+
+
+
+

Whoa! As long as you are running a Jupyter notebook with a live Python process, you should have seen the dataframe “head” output in the previous cell update to the new value of nrows. That’s because the reactive df expression in that cell captures the full pipeline of operations, automatically re-running head because the nrows has now changed.

+

We’ve done this without having to write any special callbacks or any new functions, instead using special Python objects that capture the operations you’ve invoked and replay them as needed when inputs change.

+

These updates should happen immediately (not only when the code cell finishes executing):

+
+
+
import time
+
+for i in range(4,9):
+    nrows.rx.set_input(i)
+    time.sleep(1)
+
+
+
+
+

You should see the previous df.head output react to each time nrows is changed, updating to reflect the current state.

+

We can get more complicated if we want, with a much more complex pipeline, but still matching the same code you’d write for a non-reactive Pandas DataFrame:

+
+
+
import numpy as np
+
+style = rx('color: white; background-color: {color}')
+color = rx('darkblue')
+
+def highlight_max(s, props=''):
+    if s.dtype.kind not in 'f':
+        return np.full_like(s, False)
+    return np.where(s == np.nanmax(s.values), props, '')
+
+styled_df = df.head(nrows).style.apply(highlight_max, props=style.format(color=color), axis=0)
+
+styled_df
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
 speciesislandbill_length_mmbill_depth_mmflipper_length_mmbody_mass_gsexyear
0AdelieTorgersen39.10000018.700000181.0000003750.000000male2007
1AdelieTorgersen39.50000017.400000186.0000003800.000000female2007
2AdelieTorgersen40.30000018.000000195.0000003250.000000female2007
3AdelieTorgersennannannannannan2007
4AdelieTorgersen36.70000019.300000193.0000003450.000000female2007
5AdelieTorgersen39.30000020.600000190.0000003650.000000male2007
6AdelieTorgersen38.90000017.800000181.0000003625.000000female2007
7AdelieTorgersen39.20000019.600000195.0000004675.000000male2007
8AdelieTorgersen34.10000018.100000193.0000003475.000000nan2007
9AdelieTorgersen42.00000020.200000190.0000004250.000000nan2007
+
+
+

Here we’ve made two additional reactive values (style and color), and written a Pandas pipeline that uses those values using precisely the same syntax you would with a regular Pandas expression. Since this is now a reactive Pandas expression, it will re-run whenever any of those changes. To see, try executing each of the following commands, one by one:

+
+
+
color.rx.set_input('red');
+
+
+
+
+
+
+
nrows.rx.set_input(nrows.rx.resolve()+2);
+
+
+
+
+
+
+
color.rx.set_input('darkblue');
+
+
+
+
+

In the code above, we made reactive strings, numbers, and DataFrame expressions. You can also make functions reactive, which lets you make the URL reactive as well:

+
+
+
url = rx(URL)
+df = rx(pd.read_csv)(url)
+df.head(2)
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
speciesislandbill_length_mmbill_depth_mmflipper_length_mmbody_mass_gsexyear
0AdelieTorgersen39.118.7181.03750.0male2007
1AdelieTorgersen39.517.4186.03800.0female2007
+
+
+
+
+
url.rx.set_input('https://datasets.holoviz.org/gapminders/v1/gapminders.csv');
+
+
+
+
+
+
+
url.rx.set_input(URL);
+
+
+
+
+

Here, df is no longer wrapping up a specific DataFrame and capturing operations on it, it’s wrapping up the read_csv call that generates the DataFrame originally, but it all still works just the same. As you can see, reactive expressions let you write code just as you usually would, but then separately control all the reactive elements of it.

+

Note that we have been using Jupyter Notebook cells as a way to change these reactive values, but if you imagine using a widgets from ipywidgets or Panel instead, you can see how easy it is to create a reactive computation or application with user-controllable options.

+
+
+

Reactive Functions#

+

Ok, now that you’ve seen reactive expressions in action, let’s dive into how this all works. We’ll first write a simple, non-reactive function to add two arguments:

+
+
+
def add(a, b):
+    print(f'adding {a=} and {b=}')
+    return a + b
+
+add(3, 7)
+
+
+
+
+
adding a=3 and b=7
+
+
+
10
+
+
+
+
+

Now, let’s make a Parameterized class with some Parameters, here named a and b, that we’ll want to add together reactively. We will also import param.ipython to install support for displaying “live” reactive components in an IPython or Jupyter notebook, re-rendering themselves when the inputs change.

+
+
+
import param
+import param.ipython
+
+class Parameters(param.Parameterized):
+    
+    a = param.Number(1)
+
+    b = param.Number(0)
+
+    run = param.Event()
+    
+p = Parameters()
+
+
+
+
+

Ok, now we can use param.bind to “bind” parameters a and b to create a reactive function:

+
+
+
reactive_add = param.bind(add, p.param.a, p.param.b)
+
+reactive_add
+
+
+
+
+
adding a=1 and b=0
+
+
+
5
+
+
+
+
+

As you can see, reactive_add works just like add, in that it adds two arguments, but in this case it’s taking the value of the a and b Parameters of p. Parameter a has been “bound” to the first argument and b to the second, and if either of them changes, the result changes. So if we change p.a to 5, the output above changes immediately (it “reacts”).

+
+
+
p.a += 4
+
+
+
+
+
adding a=5 and b=0
+
+
+
+
+

We can also call the reactive function explicitly to return the current result as a concrete, no longer reactive value:

+
+
+
reactive_add()
+
+
+
+
+
adding a=5 and b=0
+
+
+
5
+
+
+
+
+

The difference between reactive_add and reactive_add() is that the first one is a function, whose display will automatically update in IPython/Jupyter thanks to the extension loaded above, while the second is a specific number (the result of calling that function a single time, never to be updated further):

+
+
+
print(type(reactive_add), type(reactive_add()))
+
+
+
+
+
adding a=5 and b=0
+<class 'function'> <class 'int'>
+
+
+
+
+

param.bind follows the semantics of Python’s functools.partial, and so if you only partially bind the required arguments, you’ll get a function of the remaining arguments:

+
+
+
add_b = param.bind(add, p.param.a)
+add_b
+
+
+
+
+
<function param.reactive.bind.<locals>.wrapped(*wargs, **wkwargs)>
+
+
+
+
+
+
+
add_b(5)
+
+
+
+
+
adding a=5 and b=5
+
+
+
10
+
+
+
+
+

Note that you can bind any accepted type to make a reactive function, not just Parameters, but static values won’t trigger reactive updates (here 38 will always be the same value, while the result will depend on the current value of p.param.a).

+
+
+
param.bind(add, p.param.a, b=38)
+
+
+
+
+
adding a=5 and b=38
+
+
+
43
+
+
+
+
+
+
+

Reactive Expressions#

+

While reactive functions are very useful and allow writing arbitrarily complex logic, they still require writing a Python function definition, which can be verbose to write and difficult to read. With a reactive expression instead of an explicitly defined function, you can wrap any object or parameter value and apply operations on it, just as if you are working with the actual object, but now with reactive outputs. In other words, the reactive expression acts as a proxy for the underlying value, while supporting (almost) all operations that can be performed with the original object.

+
+

Using Parameters#

+

As an example, let’s create reactive proxies for the a and b parameters and add them together:

+
+
+
q = Parameters()
+
+expr = q.param.a.rx() + q.param.b.rx() + 3
+
+expr
+
+
+
+
+
8
+
+
+
+
+

The resulting reactive expression now reflects the result of this operation and will update automatically when one of the inputs to the operation changes, e.g. if we update parameter a:

+
+
+
q.a += 2
+
+
+
+
+
+
+

Resolving the expression#

+

Reactive objects generally just provide whatever API the underlying object has, but there are a few extra reactive-specific methods also provided. In order to avoid any clashes between the namespace of the reactive expression and the object it is wrapping, the extra methods are in a special namespace called .rx.

+

For instance, to resolve the current value of the expression into the current value as a static (non-reactive) object, we can call .rx.resolve():

+
+
+
expr.rx.resolve()
+
+
+
+
+
6
+
+
+
+
+

The number displayed above is no longer tied to the reactive expression, it is its concrete output value, and so it will not update when a or b changes:

+
+
+
q.b += 2
+
+
+
+
+
+
+

Using literal objects as inputs#

+

The convenient param.rx function lets you make just about anything reactive, without having to first define a new Parameterized object with explicit Parameters. E.g. we can create a reactive object from a static, literal value, such as a string:

+
+
+
string_template = param.rx('Hello {name}!')
+
+string_template
+
+
+
+
+
'Hello {name}!'
+
+
+
+
+

The reactive object now acts like a string so we can use the .format method to fill in the string_template with another reactive expression:

+
+
+
name = param.rx('world')
+
+str_expr = string_template.format(name=name)
+
+str_expr
+
+
+
+
+
'Hello there!'
+
+
+
+
+
+
+

Setting the input value#

+

To update the input to a rx object we can use the .rx.set_input(new) method:

+
+
+
name.rx.set_input('there')
+
+str_expr.rx.resolve()
+
+
+
+
+
'Hello there!'
+
+
+
+
+
+
+

Functions#

+

In some cases you might not have a concrete value as a starting point and start with a function instead. A fully bound function can be converted to a reactive expression letting you work with the output of a function as if it was a concrete value:

+
+
+
param.bind(add, p.param.a, p.param.b).rx() / 2
+
+
+
+
+
adding a=5 and b=0
+
+
+
2.5
+
+
+
+
+
+
+

Special Methods & Limitations#

+

A reactive proxy behaves like the underlying object it is wrapping, but only to the extent that Python allows. +Certain operations cannot be implemented in this way, e.g. Python will not allow the len operation to return anything but a integer and the is statement always checks the immediate identity of its two operands. Reactive doesn’t support operator keywords (i.e. and, or, not, in and is), control flow keywords (i.e. if, elif, else), ternary conditional expressions (i.e. a if condition else b), and only supports iteration keywords to a limited extent (i.e. for or while). Although it does implement an iterator interface this will only work well for fixed length collections.

+
+

Special methods#

+

Therefore reactive implements certain operations as special methods that exist on the .rx namespace alongside rx.set and rx.resolve:

+
    +
  • .rx.bool(): Reactive version of bool(), casting the output value to a Boolean.

  • +
  • .rx.in_(): Reactive version of in, testing if value is in the provided collection.

  • +
  • .rx.is_(): Reactive version of is, testings the object identity against another object.

  • +
  • .rx.is_not(): Reactive version of is not, testing the absence of object identity with another object.

  • +
  • .rx.len(): Reactive version of len(), returning the length of the expression

  • +
  • .rx.pipe(): Applies the given function (with static or reactive arguments) to this object.

  • +
  • .rx.when(): Generates a new expression that only updates when the provided dependency updates.

  • +
  • .rx.where(): Returns either the first or the second argument, depending on the current value of the expression.

  • +
+
+
+

.rx.bool()#

+

Casts the current value to a Boolean True or False value:

+
+
+
rx(1).rx.bool()
+
+
+
+
+
True
+
+
+
+
+
+
+

.rx.in_(arg)#

+

Checks if current value is .in_ the other collection

+
+
+
rx(2).rx.in_([1, 2, 3])
+
+
+
+
+
True
+
+
+
+
+
+
+

.rx.is_(arg)#

+

Checks the identity of the current value is the same as the argument to .is_

+
+
+
rx(None).rx.is_(None)
+
+
+
+
+
True
+
+
+
+
+
+
+

.rx.is_not(arg)#

+

Checks the identity of the current value is not the same as the argument to .is_not

+
+
+
rx(None).rx.is_not(None)
+
+
+
+
+
False
+
+
+
+
+
+
+

.rx.len()#

+

Returns the length of the object

+
+
+
rx([1, 2, 3]).rx.len()
+
+
+
+
+
3
+
+
+
+
+
+
+

.rx.pipe(func, *args, **kwargs)#

+

Pipes the current value into a function as the first argument, passing in additional positional and keyword arguments if provided:

+
+
+
rx(1).rx.pipe(add, 2)
+
+
+
+
+
adding a=1 and b=2
+
+
+
3
+
+
+
+
+
+
+
rx(8).rx.pipe(str)
+
+
+
+
+
'8'
+
+
+
+
+
+
+

.rx.when(*conditions)#

+

Useful when creating UIs to declare that the expression should only update when some other parameter changes, e.g. when a user clicks a button or triggers an expensive operation through some other mechanism.

+

For instance, let’s say we have some expensive function (here simulated using time.sleep). First we bind parameters a and b to this function and create a reactive expression from this function.

+
+
+
import time
+
+def expensive_function(a, b):
+    print(f'multiplying {a=} and {b=}')
+    time.sleep(2)
+    return a * b
+
+p = Parameters()
+
+expensive_expr = param.bind(expensive_function, p.param.a, p.param.b).rx()
+
+
+
+
+
multiplying a=1 and b=0
+
+
+
+
+

The problem we face is that if we use this expensive_expr whenever a or b are changed, then the expensive computation gets triggered twice if we want to change both a and b. We could use p.param.update() to change them in bulk in this particular case, but since that’s not always sufficient, here we’ll gate the computation behind a third variable, e.g. the run Event parameter on the Parameters class.

+
+
+
gated_expr = expensive_expr.rx.when(p.param.run)
+
+gated_expr
+
+
+
+
+
8
+
+
+
+
+

We can now safely change variables a and b separately without triggering the computation:

+
+
+
p.a = 2
+p.b = 4
+
+gated_expr.rx.resolve()
+
+
+
+
+
0
+
+
+
+
+

But when we trigger the run parameter the expression will re-compute:

+
+
+
p.param.trigger('run')
+
+gated_expr.rx.resolve()
+
+
+
+
+
multiplying a=2 and b=4
+
+
+
8
+
+
+
+
+
+
+

.rx.where(x, y)#

+

Allows writing ternary conditions using the reactive paradigm. Ordinarily you can write something like this:

+
value_a if some_condition else value_b
+
+
+

to return value_a or value_b depending on some condition. However, Python does not allow overriding if, so if statements are not re-evaluated when the condition changes, and instead we have to rewrite this case using where.

+

First we will declare a condition, which here is simply a reactive expression wrapping a Boolean value:

+
+
+
condition = rx(True)
+
+
+
+
+

Now let’s say we want to return either Parameter a or b depending on whether the condition is True or False. We can simply pass the values to .where():

+
+
+
p = Parameters(a=1, b=2)
+
+ternary_expr = condition.rx.where(p.param.a, p.param.b)
+
+ternary_expr
+
+
+
+
+
5
+
+
+
+
+

Since the initial value is True it returns the current value of a, which is 1. However when we set the value to False it will return the value of b:

+
+
+
condition.rx.set_input(False)
+
+ternary_expr.rx.resolve()
+
+
+
+
+
2
+
+
+
+
+

Importantly, if we now change b the result will be reflected by the expression, reactively unless we explicitly resolve the result:

+
+
+
p.b = 5
+
+ternary_expr.rx.resolve()
+
+
+
+
+
5
+
+
+
+
+

Here the expression value depends only on b thanks to the where condition, and thus changes to a will no longer trigger any downstream updates until the condition is reversed again.

+
+
+
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/user_guide/Serialization_and_Persistence.html b/user_guide/Serialization_and_Persistence.html new file mode 100644 index 0000000..2c4d28e --- /dev/null +++ b/user_guide/Serialization_and_Persistence.html @@ -0,0 +1,1129 @@ + + + + + + + + + + + + Serialization and Persistence — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

Serialization and Persistence#

+

Parameterized objects are declarative, explicitly defining a set of values for their parameters. This set of values constitutes the (parameter) state of the object, and this state can be saved (“serialized”), transmitted (if appropriate), and restored (“deserialized”) in various ways, so that object state can be sent from one Python session to another, restored from disk, configured using a text file, and so on.

+

Param offers several independent serialization mechanisms for a Parameterized object, each used for very different purposes:

+
    +
  • Pickle: creates a Python pickle file containing not just the Parameters, but potentially any other state of the object. A pickle file is not human readable, and is not always portable between different python versions, but it is highly complete, capturing both parameter values and also non-Parameter attributes of an object. Useful for saving the entire state of a complex object and restoring it. All objects used in pickling need to be restorable, which puts some restrictions on Parameter values (e.g. requiring named functions, not lambdas).

  • +
  • JSON: captures the state as a JSON text string. Currently and probably always limited in what can be represented, but human readable and easily exchanged with other languages. Useful for sending over a network connection, saving simple state to disk for restoring later, etc.

  • +
  • script_repr: generates a string representation in the form of Python code that, when executed, will instantiate Parameterized objects having similar state. Useful for capturing the current state in a compact, human-readable form suitable for manual editing to create a Python file. Not all Parameters will have values representable in this way (e.g. functions defined in the current namespace will not show their function definition), but this representation is generally a reasonable human-readable starting point for hand editing.

  • +
+
+

Pickling Parameterized objects#

+

Param supports Python’s native pickle serialization format. Pickling converts a Python object into a binary stream of bytes that can be stored on disk, and unpickling converts a previously pickled byte stream into an instantiated Python object in the same or a new Python session. Pickling does not capture the actual Python source code or bytecode for functions or classes; instead, it assumes you will have the same Python source tree available for importing those definitions during unpickling and only stores the fully qualified path to those definitions. Thus pickling requires that you use named functions defined in separate importable modules rather than lambdas (unnamed functions) or other objects whose code is defined only in the main namespace or in a non-importable python script.

+

Apart from such limitations, pickling is the most rich and fully featured serialization option, capable of capturing the full state of an object even beyond its Parameter values. Pickling is also inherently the least portable option, because it does include all the details of this internal state. The resulting .pkl files are not human readable and are not normally usable outside of Python or even across Python versions in some cases. Pickling is thus most useful for “snapshots” (e.g. for checkpoint-and-restore support) for a particular software installation, rather than for exporting, archiving, or configuration. See the comparison with JSON to help understand some of the tradeoffs involved in using pickles.

+
+

Using pickling#

+

Let’s look at an example of pickling and unpickling a Parameterized object:

+
+
+
import param, pickle, time
+from param.parameterized import default_label_formatter
+
+class A(param.Parameterized):
+    n = param.Number(39)
+    l = param.List(["a","b"])
+    o = param.ClassSelector(class_=param.Parameterized)
+    
+    def __init__(self, **params):
+        super(A,self).__init__(**params)
+        self.timestamp = time.time()
+    
+a = A(n=5, l=[1,"e",[2]], o=default_label_formatter.instance())
+a, a.timestamp
+
+
+
+
+
(A(l=[1, 'e', [2]], n=5, name='A00003', o=default_label_formatter(capitalize=True, name='default_label_formatter00002', overrides={}, replace_underscores=True)),
+ 1695671713.950791)
+
+
+
+
+

Here we created a Parameterized object a containing another Parameterized object nested in parameter o, with state in self.timestamp and not just in the Parameter values. To save this state to a file on disk, we can do a pickle “dump” and then delete the object so that we are sure it’s no longer around:

+
+
+
with open('data.pickle', 'wb') as f:
+    pickle.dump(a, f)
+    
+del a
+
+
+
+
+

To reload the state of a from disk, we do a pickle “load”:

+
+
+
import pickle
+
+with open('data.pickle', 'rb') as f:
+    a = pickle.load(f)
+    
+a, a.timestamp
+
+
+
+
+
(A(l=[1, 'e', [2]], n=5, name='A00003', o=default_label_formatter(capitalize=True, name='default_label_formatter00002', overrides={}, replace_underscores=True)),
+ 1695671713.950791)
+
+
+
+
+

As you can see, it restored not just the Parameter values, but the timestamp (stored in the object’s dictionary) as well.

+

Here we are depending on the class definition of A actually being in memory. If we delete that definition and try to unpickle the object again, it will fail:

+
+
+
del A
+
+with param.exceptions_summarized():
+    with open('data.pickle', 'rb') as f:
+        a = pickle.load(f)
+
+
+
+
+
AttributeError: Can't get attribute 'A' on <module '__main__'>
+
+
+
+
+

Notice how the pickle has stored the fact that class A is defined in the main namespace, but because __main__ is not an importable module, unpickling fails. Had A been defined in a module available for importing, unpickling would have succeeded here even if A had never previously been loaded.

+

To use pickling in practice, you’ll need to ensure that all functions and classes are named (not lambdas) and defined in some importable module, not just inline here in a notebook or script or command prompt. Even so, pickling can be very useful as a way to save and restore state of complex Parameterized objects.

+
+
+

Pickling limitations and workarounds#

+

As you develop a module using Param, you’ll need to pay attention to a few technical issues if you want to support pickling:

+
    +
  1. Callable parameter values: If you provide any param.Callable, param.Hooklist, or other parameters that can accept callable objects to your users, you will need to warn them that none of those can be set to unnamed (lambda) functions or to one-off functions defined in the main namespace if they want to use pickling. Of course, you can accept such values during initial development when you may not care about pickling, but once things are working, move the one-off function to a proper importable module and then it will be safe to use as a picklable value. One way to make this work smoothly is to create param.ParameterizedFunction objects or other “function object” classes (classes whose instances are callable like functions but which may have state and are fully picklable); see e.g. the numbergen module for examples.

  2. +
  3. Skipping Parameters that should not be pickled: In some cases, you may not want the value of a given Parameter to be pickled and restored even while other state is being serialized. For instance, a Parameter whose value is set to a particular file path might cause errors if that path is restored when the pickle is loaded on a different system or once the file no longer exists. To cover such rare but potentially important cases, the Parameter can be defined with pickle_default_value=False (normally True), so that the instantaneous value is usable but won’t be saved and restored with pickle.

  4. +
  5. Customizing settting and getting state: You may find that your Parameter or Parameterized objects have other state that you need to handle specially, whether that’s to save and restore data that isn’t otherwise picklable, or to ignore state that should not be pickled. For instance, if your object’s dictionary contains some object that doesn’t support pickling, then you can add code to omit that or to serialize it in some special way that allows it to be restored, e.g. by extracting a state dictionary fom it and then restoring it from the dictionary later. See the pickle docs for the __getstate__ and __setstate__ methods that you can implement on your Parameter or Parameterized objects to override this behavior. Be sure to call super(YourClass,self).__setstate__(state) or the getstate equivalent so that you also store parameters and dictionary values as usual, if desired.

  6. +
  7. Loading old pickle files: If you use pickles extensively, you may find yourself wanting to support pickle files generated by an older version of your own code, even though your code has since changed (with renamed modules, classes, or parameters, or options that are no longer supported, etc.). By default, unpickling will raise an exception if it finds information in your pickle file that does not match the current Python source code, but it is possible to add custom handling to translate old definitions to match current code, discard no-longer-used options, map from a previous approach into the current approach, etc. You can use __getstate__ and __setstate__ on your top-level object or on specific other classes to do just about anything like this, though it can get complicated to reason about. Best practice is to store the module version number or other suitable identifier as an attribute or Parameter on the top-level object to declare what version of the code was used to create the file, and you can then read this identifier later to determine whether you need to apply such conversions on reloading.

  8. +
+
+
+
+

Serializing with JSON#

+

JSON is a human-readable string representation for nested dictionaries of key-value pairs. Compared to pickle, JSON is a much more limited representation, using a fixed set of types mapped to string values, and not natively supporting Python-specific types like tuples or custom Python objects. However, it is widely accepted across computer languages, and because it is human readable and editable and omits the detailed internal state of objects (unlike pickle), JSON works well as an interchange or configuration format.

+

Param’s JSON support is currently fairly limited, with support for serializing and deserializing individual (not nested) Parameterized objects. It is currently primarily used for synchronizing state “across the wire”, e.g. between multiple apps running on different machines that communicate changes to shared state (e.g. for a remote GUI), but as proposed in issue#520 it could be extended to be a general configuration and specification mechanism by adding conventions for specifying a Parameterized type for an object and its nested objects.

+

To see how it currently works, let’s start with a Parameterized object containing Parameters of different types:

+
+
+
import param, datetime, numpy as np, pandas as pd
+
+ndarray = np.array([[1,2,3],[4,5,6]])
+df = pd.DataFrame({'A':[1,2,3], 'B':[1.1,2.2,3.3]})
+
+simple_list = [1]
+
+class P(param.Parameterized):
+    a = param.Integer(default=5, doc='Int', bounds=(2,30), inclusive_bounds=(True, False))
+    e = param.List([1,2,3], class_=int)
+    g = param.Date(default=datetime.datetime.now())
+    l = param.Range(default=(1.1,2.3), bounds=(1,3))
+    m = param.String(default='baz', allow_None=True)
+    s = param.DataFrame(default=df, columns=(1,4), rows=(2,5))
+
+p = P(a=29)
+p
+
+
+
+
+
/tmp/ipykernel_3102/1070590161.py:10: ParamDeprecationWarning: The 'class_' attribute on 'List' is deprecated. Use instead 'item_type'
+  e = param.List([1,2,3], class_=int)
+
+
+
P(a=29, e=[1, 2, 3], g=datetime.datetime(2023, 9, 25, 19, 55, 14, 193836), l=(1.1, 2.3), m='baz', name='P00004', s=   A    B
+0  1  1.1
+1  2  2.2
+2  3  3.3)
+
+
+
+
+

To serialize this Parameterized object to a JSON string, call .serialize_parameters() on it:

+
+
+
s = p.param.serialize_parameters()
+s
+
+
+
+
+
'{"name": "P00004", "a": 29, "e": [1, 2, 3], "g": "2023-09-25T19:55:14.193836", "l": [1.1, 2.3], "m": "baz", "s": [{"A": 1, "B": 1.1}, {"A": 2, "B": 2.2}, {"A": 3, "B": 3.3}]}'
+
+
+
+
+

Notice that the serialization includes not just the values set specifically on this instance (a=29), but also all the default values inherited from the class definition.

+

You can easily select only a subset to serialize, if you wish:

+
+
+
p.param.serialize_parameters(subset=['a','m'])
+
+
+
+
+
'{"a": 29, "m": "baz"}'
+
+
+
+
+

The JSON string can be saved to disk, sent via a network connection, stored in a database, or for any other usage suitable for a string.

+

Once you are ready to deserialize the string into a Parameterized object, you’ll need to know the class it came from (here P) and can then call its deserialize_parameters method to get parameter values to use in P’s constructor:

+
+
+
p2 = P(**P.param.deserialize_parameters(s))
+p2
+
+
+
+
+
P(a=29, e=[1, 2, 3], g=datetime.datetime(2023, 9, 25, 19, 55, 14, 193836), l=(1.1, 2.3), m='baz', name='P00004', s=   A    B
+0  1  1.1
+1  2  2.2
+2  3  3.3)
+
+
+
+
+

As you can see, we have successfully serialized our original object p into a new object p2, which could be in a different Python process on a different machine or at a different date.

+
+

JSON limitations and workarounds#

+

To see the limitations on Param’s JSON support, let’s look at how it works in more detail. Because the result of serialization (s above) is a valid JSON string, we can use the json library to unpack it without any knowledge of what Parameterized class it came from:

+
+
+
import json
+dj = json.loads(s)
+dj
+
+
+
+
+
{'name': 'P00004',
+ 'a': 29,
+ 'e': [1, 2, 3],
+ 'g': '2023-09-25T19:55:14.193836',
+ 'l': [1.1, 2.3],
+ 'm': 'baz',
+ 's': [{'A': 1, 'B': 1.1}, {'A': 2, 'B': 2.2}, {'A': 3, 'B': 3.3}]}
+
+
+
+
+

The result is a Python dictionary of name:value pairs, some of which you can recognize as the original type (e.g. a=29), others that have changed type (e.g. l=(1.1,2.3) or s=pd.DataFrame({'A':[1,2,3], 'B':[1.1,2.2,3.3]})), and others that are still a string encoding of that type (e.g. g=datetime.datetime(...))). If you try to pass this dictionary to your Parameterized constructor, any such value will be rejected as invalid by the corresponding Parameter:

+
+
+
with param.exceptions_summarized():
+    P(**dj)
+
+
+
+
+
ValueError: Date parameter 'P.g' only takes datetime and date types, not <class 'str'>.
+
+
+
+
+

That’s why instead of simply json.loads(s), we do P.param.deserialize_parameters(s), which uses the knowledge that P.l is a tuple parameter to convert the resulting list [1.1, 2.3] into a Python tuple (1.1, 2.3) as required for such a parameter:

+
+
+
print(dj['l'])
+print(p2.l)
+
+
+
+
+
[1.1, 2.3]
+(1.1, 2.3)
+
+
+
+
+

Similarly, parameters of type param.Array will unpack the list representation into a NumPy array, param.DataFrame unpacks the list of dicts of list into a Pandas DataFrame, etc. So, the encoding for your Parameterized object will always be standard JSON, but to deserialize it fully into a Parameterized, you’ll need to know the class it came from, or Param will not know that the list it finds was originally a tuple, dataframe, etc.

+

For this reason, any Parameter that itself contains a Parameterized object will not be able to be JSON deserialized, since even if we knew what class it was (e.g. for param.ClassSelector(class_=param.Number), it could be some subclass of that class. Because the class name is not currently stored in the JSON serialization, there is no way to restore it. Thus there is currently no support for JSON serializing or deserializing nested Parameterized objects.

+

We do expect to add support for nested objects using something like the convention for datetime objects; see issue#520.

+
+
+

JSON Schemas#

+

If you want to use your JSON representation in a separate process where Param is not available or perhaps in a different language altogether, Param can provide a JSON schema that specifies what type you are expecting for each Parameter. The schema for a given Parameterized can be obtained using the schema method:

+
+
+
p.param.schema()
+
+
+
+
+
{'name': {'anyOf': [{'type': 'string'}, {'type': 'null'}],
+  'description': 'String identifier for this object.',
+  'title': 'Name'},
+ 'a': {'type': 'integer',
+  'minimum': 2,
+  'exclusiveMaximum': 30,
+  'description': 'Int',
+  'title': 'A'},
+ 'e': {'type': 'array', 'items': {'type': 'integer'}, 'title': 'E'},
+ 'g': {'type': 'string', 'format': 'date-time', 'title': 'G'},
+ 'l': {'type': 'array',
+  'minItems': 2,
+  'maxItems': 2,
+  'additionalItems': {'type': 'number', 'minimum': 1, 'maximum': 3},
+  'title': 'L'},
+ 'm': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'title': 'M'},
+ 's': {'type': 'array',
+  'items': {'type': 'object', 'minItems': 1, 'maxItems': 4},
+  'minItems': 2,
+  'maxItems': 5,
+  'title': 'S'}}
+
+
+
+
+

Once you have the schema, you can validate that a given JSON string matches the schema, i.e. that all values included therein match the constraints listed in the schema:

+
+
+
from jsonschema import validate
+d = json.loads(s)
+full_schema = {"type" : "object", "properties" : p.param.schema()}
+validate(instance=d, schema=full_schema)
+
+
+
+
+

If one of the parameter values fails to match the provided schema, you’ll get an exception:

+
+
+
d2 = d.copy()
+d2['a']='astring'
+
+with param.exceptions_summarized():
+    validate(instance=d2, schema=full_schema)
+
+
+
+
+
ValidationError: 'astring' is not of type 'integer'
+
+Failed validating 'type' in schema['properties']['a']:
+    {'description': 'Int',
+     'exclusiveMaximum': 30,
+     'minimum': 2,
+     'title': 'A',
+     'type': 'integer'}
+
+On instance['a']:
+    'astring'
+
+
+
+
+

The param.schema() call accepts the same subset argument as .param.serialize_parameters(), letting you serialize and check only a subset of the parameters if appropriate.

+

You can also supply a safe=True argument that checks that all parameter values are guaranteed to be serializable and follow the given schema. This lets you detect if there are any containers or parameters whose type is not fully specified:

+
+
+
with param.exceptions_summarized():
+    full2 = {"type" : "object", "properties" : p.param.schema(safe=True)}
+    validate(instance=d, schema=full2)
+
+
+
+
+
UnsafeserializableException: DataFrame is not guaranteed to be safe for serialization as the column dtypes are unknown
+
+
+
+
+
+
+
+

script_repr#

+

Parameterized objects can be constructed through a series of interactive actions, either in a GUI or command line, or as the result of automated scripts and object-construction functions. Any parameter values can also be changed at any moment once that object has been created. If you want to capture the resulting Parameterized object with any such additions and changes, you can use the param.script_repr() function. script_repr returns a representation of that object and all nested Parameterized or other supported objects as Python code that can recreate the full object later. This approach lets you go flexibly from an interactive or indirect way of creating or modifying objects, to being able to recreate that specific object again for later use. Programs with a GUI interface can use script_repr() as a way of exporting a runnable version of what a user created interactively in the GUI.

+

For example, let’s construct a Parameterized object p containing Parameters whose values are themselves Parameterized objects with their own Parameters:

+
+
+
import param
+
+class Q(param.Parameterized):
+    a = param.Number(39, bounds=(0,50))
+    b = param.String("str")
+
+class P(param.Parameterized):
+    c = param.ClassSelector(default=Q(), class_=Q)
+    d = param.ClassSelector(default=param.Parameterized(), class_=param.Parameterized)
+    e = param.Range((0,1))
+    
+q = Q(b="new")
+p=P(c=q, e=(2,3))
+p
+
+
+
+
+
P(c=Q(a=39, b='new', name='Q00048'), d=Parameterized(name='Parameterized00051'), e=(2, 3), name='P00049')
+
+
+
+
+

We can get a script representation for this object by calling script_repr(p):

+
+
+
print(param.script_repr(p))
+
+
+
+
+
import __main__
+import param
+import param.parameterized
+
+__main__.P(c=__main__.Q(b='new'),
+
+        d=param.parameterized.Parameterized(),
+
+        e=(2,3))
+
+
+
+
+

As you can see, this representation encodes the fact that P was defined in the main namespace, generated inside this notebook. As you might expect, this representation has the same limitation as for pickle – only classes that are in importable modules will be runnable; you’ll need to save the source code to your classes in a proper Python module if you want the resulting script to be runnable. But once you have done that, you can use the script_repr to get a runnable version of your Parameterized object no matter how you created it, whether it was by selecting options in a GUI, adding items via a loop in a script, and so on.

+
+

script_repr limitations and workarounds#

+

Apart from making sure your functions and classes are all defined in their own importable modules, there are various considerations and limitations to keep in mind if you want to support using script_repr.

+

Normally, script_repr prints only parameter values that have changed from their defaults; it is designed to generate a script as close as is practical to one that a user would have typed to create the given object. If you want a record of the complete set of parameter values, including all defaults, you can enable that behavior:

+
+
+
import param.parameterized
+param.parameterized.script_repr_suppress_defaults=True
+
+
+
+
+

The resulting output is then suitable for archiving the full parameter state of that object, even if some default later gets changed in the source code. Note that Param is not able to detect all cases where a default value is unchanged, e.g. for Parameters with instantiate=True, which will always be treated as changed since each instance has a copy of that Parameter value independent of the original default value.

+

You can control script_repr with keyword arguments:

+
    +
  • imports=[]: If desired, a list of imports that can be built up over multiple script_repr calls to collect a full set of imports required for a script. Useful with show_imports=False except on the last script_repr call. Can be an empty list or a list containing some hard-coded imports needed.

  • +
  • prefix="\n    ": Optional prefix to use before a nested object.

  • +
  • qualify=True: Whether the class’s path will be included (e.g. “a.b.C()”), otherwise only the class will appear (“C()”).

  • +
  • unknown_value=None: determines what to do where a representation cannot be generated for something required to recreate the object. Such things include non-parameter positional and keyword arguments, and certain values of parameters (e.g. some random state objects). Supplying an unknown_value of None causes unrepresentable things to be silently ignored. If unknown_value is a string, that string will appear in place of any unrepresentable things. If unknown_value is False, an Exception will be raised if an unrepresentable value is encountered.

  • +
  • separator="\n": Separator to use between parameters.

  • +
  • show_imports=True: Whether to include import statements in the output.

  • +
+

The script_repr behavior for a particular type, whether it’s a Parameterized object or not, can be overridden to provide any functionality needed. Such overrides are stored in param.parameterized.script_repr_reg, which already contains handling for list and tuple containers, various objects with random state, functions, and modules. See examples in +param.parameterized.

+
+
+
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/user_guide/Simplifying_Codebases.html b/user_guide/Simplifying_Codebases.html new file mode 100644 index 0000000..c70d97b --- /dev/null +++ b/user_guide/Simplifying_Codebases.html @@ -0,0 +1,979 @@ + + + + + + + + + + + + Simplifying Codebases — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

Simplifying Codebases#

+

Param’s just a Python library, and so anything you can do with Param you can do “manually”. So, why use Param?

+

The most immediate benefit to using Param is that it allows you to greatly simplify your codebases, making them much more clear, readable, and maintainable, while simultaneously providing robust handling against error conditions.

+

Param does this by letting a programmer explicitly declare the types and values of parameters accepted by the code. Param then ensures that only suitable values of those parameters ever make it through to the underlying code, removing the need to handle any of those conditions explicitly.

+

To see how this works, let’s create a Python class with some attributes without using Param:

+
+
+
class OrdinaryClass(object):
+    def __init__(self, a=2, b=3, title="sum"):
+        self.a = a
+        self.b = b
+        self.title = title
+    
+    def __call__(self):
+        return self.title + ": " + str(self.a + self.b)
+
+
+
+
+

As this is just standard Python, we can of course instantiate this class, modify its variables, and call it:

+
+
+
o1 = OrdinaryClass(b=4, title="Sum")
+o1.a=4
+o1()
+
+
+
+
+
'Sum: 8'
+
+
+
+
+

The same code written using Param would look like:

+
+
+
import param
+        
+class ParamClass(param.Parameterized):
+    a = param.Integer(2, bounds=(0,1000), doc="First addend")
+    b = param.Integer(3, bounds=(0,1000), doc="Second addend")
+    title = param.String(default="sum", doc="Title for the result")
+    
+    def __call__(self):
+        return self.title + ": " + str(self.a + self.b)
+
+
+
+
+
+
+
o2 = ParamClass(b=4, title="Sum")
+o2()
+
+
+
+
+
'Sum: 6'
+
+
+
+
+

As you can see, the Parameters here are used precisely like normal attributes once they are defined, so the code for __call__ and for invoking the constructor are the same in both cases. It’s thus generally quite straightforward to migrate an existing class into Param. So, why do that?

+

Well, with fewer lines of code than the ordinary class, you’ve now unlocked a whole wealth of features and better behavior! For instance, what happens if a user tries to supply some inappropriate data? With Param, such errors will be caught immediately:

+
+
+
with param.exceptions_summarized():    
+    o3 = ParamClass()
+    o3.b = -5
+
+
+
+
+
ValueError: Integer parameter 'ParamClass.b' must be at least 0, not -5.
+
+
+
+
+

Of course, you could always add more code to an ordinary Python class to check for errors like that, but it quickly gets unwieldy:

+
+
+
class OrdinaryClass2(object):
+    def __init__(self, a=2, b=3, title="sum"):
+        if type(a) is not int:
+            raise ValueError("'a' must be an integer")
+        if type(b) is not int:
+            raise ValueError("'b' must be an integer")
+        if a<0:
+            raise ValueError("'a' must be at least `0`")
+        if b<0:
+            raise ValueError("'b' must be at least `0`")
+        if type(title) is not str:
+            raise ValueError("'title' must be a string")          
+        
+        self.a = a
+        self.b = b
+        self.title = title
+    
+    def __call__(self):
+        return self.title + ": " + str(self.a + self.b)
+
+
+
+
+
+
+
with param.exceptions_summarized():    
+    OrdinaryClass2(a="f")
+
+
+
+
+
ValueError: 'a' must be an integer
+
+
+
+
+

Unfortunately, catching errors in the constructor like that won’t help if someone modifies the attribute directly, which won’t be detected as an error:

+
+
+
o4 = OrdinaryClass2()
+o4.a = "four"
+
+
+
+
+

Python will happily accept this incorrect value and will continue processing. It may only be much later, in a very different part of your code, that you see a mysterious error message that’s then very difficult to relate back to the actual problem you need to fix:

+
+
+
with param.exceptions_summarized():    
+    o4()
+
+
+
+
+
TypeError: can only concatenate str (not "int") to str
+
+
+
+
+

Here there’s no problem with the code in the cell above; o4() is fully valid Python; the real problem is in the preceding cell, which could have been in a completely different file or library. The error message is also obscure and confusing at this level, because the user of o4 may have no idea why strings and integers are getting concatenated.

+

To get a better error message, you could move those checks into the __call__ method, which would make sure that errors are always eventually detected:

+
+
+
class OrdinaryClass3(object):
+    def __init__(self, a=2, b=3, title="sum"):        
+        self.a = a
+        self.b = b
+        self.title = title
+    
+    def __call__(self):
+        if type(self.a) is not int:
+            raise ValueError("'a' must be an integer")
+        if type(self.b) is not int:
+            raise ValueError("'b' must be an integer")
+        if self.a<0:
+            raise ValueError("'a' must be at least `0`")
+        if self.b<0:
+            raise ValueError("'b' must be at least `0`")
+        if type(self.title) is not str:
+            raise ValueError("'title' must be a string")          
+
+        return self.title + ": " + str(self.a + self.b)
+
+
+
+
+
+
+
o5 = OrdinaryClass3()
+o5.a = "four"
+
+
+
+
+
+
+
with param.exceptions_summarized():    
+    o5()
+
+
+
+
+
ValueError: 'a' must be an integer
+
+
+
+
+

But you’d now have to check for errors in every single method that might use those parameters. Worse, you still only detect the problem very late, far from where it was first introduced. Any distance between the error and the error report makes it much more difficult to address, as the user then has to track down where in the code a might have gotten set to a non-integer.

+

With Param you can catch such problems at their start, as soon as an incorrect value is provided, when it is still simple to detect and correct it. To get those same features in hand-written Python code, you would need to provide explicit getters and setters, which is made easier with Python properties and decorators, but is still quite unwieldy:

+
+
+
class OrdinaryClass4(object):
+    def __init__(self, a=2, b=3, title="sum"):
+        self.a = a
+        self.b = b
+        self.title = title
+    
+    @property
+    def a(self): return self.__a
+    @a.setter
+    def a(self, a):
+        if type(a) is not int:
+            raise ValueError("'a' must be an integer")
+        if a < 0:
+            raise ValueError("'a' must be at least `0`")
+        self.__a = a
+        
+    @property
+    def b(self): return self.__b
+    @b.setter
+    def b(self, b):
+        if type(b) is not int:
+            raise ValueError("'a' must be an integer")
+        if b < 0:
+            raise ValueError("'a' must be at least `0`")
+        self.__b = b
+
+    @property
+    def title(self): return self.__title
+    def title(self, b):
+        if type(title) is not string:
+            raise ValueError("'title' must be a string")
+        self.__title = title
+
+    def __call__(self):
+        return self.title + ": " + str(self.a + self.b)
+
+
+
+
+
+
+
o5=OrdinaryClass4()
+o5()
+
+
+
+
+
'sum: 5'
+
+
+
+
+
+
+
with param.exceptions_summarized():    
+    o5=OrdinaryClass4()
+    o5.b=-6
+
+
+
+
+
ValueError: 'a' must be at least `0`
+
+
+
+
+

Note that this code has an easily overlooked mistake in it, reporting a rather than b as the problem. This sort of error is extremely common in copy-pasted validation code of this type, because tests rarely exercise all of the error conditions involved.

+

As you can see, even getting close to the automatic validation already provided by Param requires 8 methods and >30 highly repetitive lines of code, even when using relatively esoteric Python features like properties and decorators, and still doesn’t yet implement other Param features like automatic documentation, attribute inheritance, or dynamic values. With Param, the corresponding ParamClass code only requires 6 lines and no fancy techniques beyond Python classes. Most importantly, the Param version lets readers and program authors focus directly on what this code actually does, which is to compute a function from three provided parameters:

+
class ParamClass(param.Parameterized):
+    a = param.Integer(2, bounds=(0,1000), doc="First addend")
+    b = param.Integer(3, bounds=(0,1000), doc="Second addend")
+    title = param.String(default="sum", doc="Title for the result")
+    
+    def __call__(self):
+        return self.title + ": " + str(self.a + self.b)
+
+
+

Even a quick skim of this code reveals what parameters are available, what values they will accept, what the default values are, and how those parameters will be used in the method. Plus the actual code of the method stands out immediately, as all the code is either parameters or actual functionality. In contrast, users of OrdinaryClass3 will have to read through dozens of lines of code to discern even basic information about usage, or else authors of the code will need to create and maintain docstrings that may or may not match the actual code over time and will further increase the amount of text to write and maintain.

+
+

Programming contracts#

+

If you think about the examples above, you can see how Param makes it simple for programmers to make a contract with their users, being explicit and clear what will be accepted and rejected, while also allowing programmers to make safe assumptions about what inputs the code may ever receive. There is no need for __call__ ever to check for the type of one of its parameters, whether it’s in the range allowed, or any other property that can be enforced by Param. Your custom code can then be much more linear and straightforward, getting right to work with the actual task at hand, without having to have reams of if statements and asserts() that disrupt the flow of the source file and make the reader get sidetracked in error-handling code. Param lets you once and for all declare what this code accepts, which is both clear documentation to the user and a guarantee that the programmer can forget about any other possible value a user might someday supply.

+

Crucially, these contracts apply not just between the user and a given piece of code, but also between components of the system itself. When validation code is expensive, as in ordinary Python, programmers will typically do it only at the edges of the system, where input from the user is accepted. But expressing types and ranges is so easy in Param, it can be done for any major component in the system. The Parameter list declares very clearly what that component accepts, which lets the code for that component ignore all potential inputs that are disallowed by the Parameter specifications, while correctly advertising to the rest of the codebase what inputs are allowed. Programmers can thus focus on their particular components of interest, knowing precisely what inputs will ever be let through, without having to reason about the flow of configuration and data throughout the whole system.

+

Without Param, you should expect Python code to be full of confusing error checking and handling of different input types, while still only catching a small fraction of the possible incorrect inputs that could be provided. But Param-based code should be dramatically easier to read, easier to maintain, easier to develop, and nearly bulletproof against mistaken or even malicious usage.

+
+
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/user_guide/index.html b/user_guide/index.html new file mode 100644 index 0000000..b53d6fd --- /dev/null +++ b/user_guide/index.html @@ -0,0 +1,707 @@ + + + + + + + + + + + + User Guide — param v2.0.0rc5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

User Guide#

+

This user guide provides detailed information about how to use Param, assuming you have worked through the Getting Started guide.

+ +
+
+
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + \ No newline at end of file