Param: Make your Python code clearer and more reliable by declaring Parameters

Overview

LinuxTests WinTests Coverage PyPIVersion PyVersion License

Param

Param is a library providing Parameters: Python attributes extended to have 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.

Param contains only two required Python files, with no external dependencies, and is provided freely for both non-commercial and commercial use under a BSD license, so that it can easily be included as part of other projects.

Please see param's website for official releases, installation instructions, documentation, and examples.

Comments
  • Add new Event parameter type

    Add new Event parameter type

    Very WIP PR to illustrate an idea we have been discussing. The API will probably change but here is the current behavior:

    image

    The idea is to add a new Trigger parameter type which would replace many uses of Action. What you want to know about a Trigger parameter is whether it has been triggered (e.g a button clicked). The value is True if the parameter has just been triggered, otherwise False (which means a trigger call has happened since not involving that parameter).

    One possibility which is more complicated is to avoid b.param.trigger('a') by setting b.a = True (setting to True triggers, whether or not the value is True already). This involves working inside __set__ which can get quite tricky.

    At this point, this PR aims to be a place to discuss this suggestion more than something to merge. The idea is that this parameter would mean https://github.com/holoviz/holoviews/pull/4611 is not necessary (though panel would need to be updated to display this parameter type as appropriate buttons).

    TODO

    • [x] Make this work with class parameters (doesn't work with Bar at the moment in the example above)
    • [ ] Improve API, possibly via __set__
    opened by jlstevens 37
  • Alternative implementation of ParamOverrides

    Alternative implementation of ParamOverrides

    I've re-implemented ParamOverrides, following the suggestion made in #85 about sharing parameter objects. This PR isn't meant for merging at this stage, I'd just like some comments on the basic idea.

    This new implementation passes all the tests (including one I added to check that dynamic overrides work), although the implementation's not yet complete (just missing some minor methods that the current ParamOverrides has). However, what I'd like to know is: is the whole idea crazy? If it's not crazy, is there a way to make the implementation simpler? I've left extra comments in the code for now to explain what I was thinking.

    In case it's easier to look at the class in one piece: https://github.com/ceball/param/blob/bug85_newParamOverrides/param/parameterized.py#L1580

    (Also, note that I haven't considered speed.)

    type-bug 
    opened by ceball 37
  • Expressing dependencies between parameters and code

    Expressing dependencies between parameters and code

    I'm pulling some suggestions out of #160 to file as a separate issue. As it turns out there are different things we might want to have param express:

    1. Relationships between parameters i.e update parameter settings based on changes to another parameter. There may be some easy way to express such relationship or there might be some code supplied by the user to link parameters (e.g using the set_hook idea)
    2. Relationships between parameters and regular code in parameterized classes that might consume parameter values and/or set them. This is what this issue is about and the idea is to express that a method might make use of a parameter and might set other parameters. If the method has output, you may make the assumption that the output will have changed when the parameters that are read by that method have changed.
    3. General specifications of input/output types of methods, functions etc. This would be very useful for some things but currently out of the scope of what we want to achieve in the short term.

    Here are my proposals to address 2. made in issue #160:

    class Example(param.Parameterized):
    
        A = param.Number(default=10)
    
        B = param.Number(default=5)
    
        @param.dependencies([A],[B])
        def link_a_to_b(self, **parameters):
            self.B = parameters['A']/2.
    

    This expresses the parameters read ([A]) and the parameters written to ([B]) using a decorator. Alternatively, you could have more granular decorators:

    class Example(param.Parameterized):
    
        A = param.Number(default=10)
    
        B = param.Number(default=5)
    
        @param.reads([A])
        @param.writes([B])
        def link_a_to_b(self, **parameters):
            self.B = parameters['A']/2.
    

    The information captured by the decorator needs to be stored somewhere. Presumably we don't want either 1) a global mapping of parameterized classes and their parameter dependencies as this would be fragile 2) distributing this information among the parameters themselves (would be very space inefficient if each parameter holds such information). This means the natural place to keep track of this is in the parameterized classes, presumably somewhere in param.Parameterized.

    The limitation of this is 1) it wouldn't be customizable per instance 2) it would be information defined once when the class is defined. Neither of these seems to be a real problem as we don't often shove/mutate methods on classes after they are defined.

    As for API, I really would like #154 tackled (putting the API onto a sub-object) first but that seems unlikely to happen. Here is one simple idea of how the information could be accessed:

    example = Example()
    reads, writes = example.param_dependencies('link_a_to_b') # OR
    reads, writes = Example.param_dependencies('link_a_to_b') 
    

    This just regurgitates what was supplied to the @param.dependencies decorator where the reads and writes might be empty lists. I'm not sure whether these lists should just contain parameter names or the parameter objects themselves. Maybe this could be an optional argument to the param_dependencies method where I would favor names by default.

    One thing worth mentioning is by making certain assumptions you could follow a chain of changes without executing user code. For instance, if you assume that changing parameter a read by method1 changes parameter b that it writes to, you might then assume that the output of method2 is changed as that method reads parameter b.

    Note that this proposal simply aims to capture the which parameters are read/written to by methods and doesn't aim to do anything with this information. I have no particular proposals for this just yet but I can imagine param offering utilities to trace the potential dependency graph of parameters and perhaps execute various sorts of callback when parameters change.

    opened by jlstevens 30
  • Defined namespace and implementation on Parameters object

    Defined namespace and implementation on Parameters object

    This PR is still WIP. There are a lot of lines changed from the very first commit as this was the sort of task I couldn't tell would be viable until it was all done.

    In short it moves most of the code of Parameterized onto a param objects of type Parameters which also acts as a namespace. The goal is to make this the face of the public API cleaning up the namespace of classes subclassed by users. Here is an example for a bothmethod params:

    image

    HOW IT WORKS

    • Parameters is instantiated by the metaclass or the regular constructor.
    • All methods use self_ as the first argument.
    • Classmethods have the first line cls = self_.cls after which the code is unchanged.
    • Bothmethods have the first line self_or_cls = self_.cls if self_.self is None else self_.self after which the code is unchanged.
    • Instance methods have the first line self = self_.self after which the code is unchanged.
    • Double underscore methods need special handling (see below) but thankfully they are rare.

    Notes:

    • The param object is per instance when necessary allowing it to hold state either at the class or instance level: this will be important for recording information regarding parameter dependencies etc.
    • Methods decorated with @as_uninitialized are used in the Parameterized constructor and I have left them on that class.
    • I have left the 'special' methods on Parameterized (e.g __repr__)
    • The only exception to the above is _instantiate_param which I can move as it used __dict__ and is used from the Parameterized constructor via _setup_params
    • I have tried to organized methods by their type: classmethods, then bothmethods and finally instance methods. Within these groups I aimed for rough semantic grouping.
    • Double underscore methods need to be moved to Parametersand accessed through self_ to avoid Python name mangling issues. This came up for __db_print in particular.
    • self_or_cls, cls_or_self, cls_or_slf or slf_or_cls? I have seen at least three of these...
    • The actual API could do with some clean up. It is definitely redundant in places...

    TODO

    • [x] Fix issue with existing nosetests
    • [x] Transfer methods for ParameterizedFunction? [Yes except for .instance]
    • [x] Add more tests [copy existing tests and update]
    • [x] Transfer docstrings to aliased methods?
    • [x] Update internal API to use .param namespace so we can just delete the aliases when the time comes.
    • [x] We need a decorator or some other approach to issue deprecation warnings when not using the param object to migrate users to the namespace object.
    • [x] Try to move the @as_uninitialized and special methods too? [Yes]
    opened by jlstevens 29
  • Add support for instance parameters

    Add support for instance parameters

    This PR implements the notion of an instance parameter which can be accessed using a new API. All parameters can in theory become instance parameters (as long as the new per_instance slot is set to True). The main balance to strike here is that a) we do not want to pay the cost of copying parameters for all instances and b) we do not want users to have to add any special boilerplate to get instance parameters.

    The approach I've therefore taken is to only make a copy of a parameter when it is actually needed. This means that all existing param code will never pay the cost of making instance parameters, there's only two situations where the per instance copy is made:

    1. When a instance parameter attribute is watched. This is because you do not want events triggered by changes on the class parameter to trigger events on the instance parameter and vice versa.
    2. The second situation when a copy is made is when one of the new APIs is used to access the parameter on an instance, e.g. when you access instance.param.param_name or instance.param['param_name']. This API will make it easy to change the attributes of instance parameters, but the old obj.params()/obj.param.params() method is unaffected by this.

    Leaving the old API unaffected will ensure that old param code never pays the costs associated with instance parameters.

    • [x] Add new parameterized.param.__getitem__ and parameterized.param.__getattr__ accessors for parameters
    • [x] Modify setters to ensure they use instance parameters for validation
    • [x] Ensure that watching instance parameter attributes makes copies
    • [x] Add tests
    opened by philippjfr 26
  • Subclassing Parameter

    Subclassing Parameter

    Hello,

    i try to add my own information to param.Parameter instances by subclassing it

    here is my attempt (the additional information that i want to store in parameters is whether they should remain enabled in the graphic interface when a run has started)

    import param as pm
    
    # Add run_enabled slot to pm.Parameter classes
    class RunEnabledInfo:
    
        __slots__ = ['run_enabled']
    
        def __init__(self, *args, run_enabled=None, **kwargs):
            super(MyBoolean, self).__init__(*args, **kwargs)
            self.run_enabled = run_enabled
    
    class MyBoolean(pm.Boolean, RunEnabledInfo):
        pass
    
    class MyNumber(pm.Number, RunEnabledInfo):
        pass
    

    But i get

    Traceback (most recent call last):
      File "E:/Users/Thomas/Python/Naivia/AlphaI/test.py", line 18, in <module>
        class MyBoolean(pm.Boolean, RunEnabledInfo):
      File "C:\ProgramData\Anaconda3\lib\site-packages\param\parameterized.py", line 503, in __new__
        return type.__new__(mcs,classname,bases,classdict)
    TypeError: multiple bases have instance lay-out conflict
    

    The problem seems to be with MyBoolean inheriting from two classes. Indeed the following code works, but i wouldn't like to rewrite it for every possible parameter type! Any suggestion how to do?

    class MyBoolean(pm.Boolean):
    
        __slots__ = ['run_enabled']
    
        def __init__(self, *args, run_enabled=None, **kwargs):
            super(MyBoolean, self).__init__(*args, **kwargs)
            self.run_enabled = run_enabled
    
    status: discussion 
    opened by thomasdeneux 23
  • [WIP] Defined pre_set_hooks and post_set_hooks for Parameters

    [WIP] Defined pre_set_hooks and post_set_hooks for Parameters

    This PR is a prototype that replaces set_hook on Number with a more general system of pre- and post- setting hooks. This may be useful for things like linking streams or eventual unit support in param.

    An example of what this might be useful for is shown in ioam/holoviews#1740.

    I'm not quite sure about the appropriate signatures for the hooks right now and this PR will probably need quite a bit of discussion before we are agreed on the appropriate approach.

    opened by jlstevens 22
  • ParameterizedMetaclass now sets  __init__ method docstring

    ParameterizedMetaclass now sets __init__ method docstring

    Introduction

    This implements my suggestion for better IPython support (#71).

    In the end, this was surprisingly easy to implement! Nothing particularly fancy is going on here but I have made this feature optional. You can disable this behavior using the DOCSTRING_SIGNATURE global variable.

    Given that the time taken for class definition (e.g. on import) is rarely a performance issue, this global flag might not be necessary (assuming you are happy enabling this behavior by default).

    Demo

    
    class Foo(param.Parameterized):
        """
        This is the Foo class.
        """
    
        foo = param.Number(default=42)
    
        def __init__(self, **kwargs):
            super(Foo, self).__init__(**kwargs)
    

    Now if in IPython Notebook I do:

    >>> Foo(
    

    I see the following pop-up message:

    Foo(self, **kwargs)
    
    Foo(*args, **kwargs, foo=42)
    

    (The first useless line is automatically generated by IPython - it would be nice to suppress it!)

    If I now press the + button, the pop-up expands to show the following message underneath:

    This is the Foo class.
    

    Note that if a docstring is explicitly supplied to the __init__ method, it will be left untouched.

    The crucial features is that you can now tab-complete the 'foo' keyword and see a list all the parameters by pressing TAB (before a unique match is specified).

    Limitations

    • I simply sort all the keywords alphanumerically. A fancier implementation could list parameters according to the method resolution order (mro).
    • The values used in the signature are not updated if the user overrides the default values of class parameters.
    • Param seems to do something special if there is no __init__ for the particular subclass. For instance:
    class Bar(Foo):
    
        bar = param.String(default='bar')
    
    >>> print Bar.__init__.__doc__
            Initialize this Parameterized instance.
    
            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.
    
    • The auto-generated signature created by IPython is useless and annoying. Maybe this is something we could disable for Parameterized objects in the IPython extension?
    • Perhaps if the output is particularly good, this could replace the %params magic, listing all the parameters together with their docstrings? Note that pressing the ^ button expands all the output in the pager (which is where the %param magic also displays its output).
    • No fancy string formatting. Perhaps this is a feature. :-)

    Conclusion

    For now, I just want to sketch out a basic implementation in this PR. The inclusion of fancier features and improvements now depend on your feedback!

    Edit: Bar inherits from Foo.

    opened by jlstevens 21
  • param.DataFrame not accepting input

    param.DataFrame not accepting input

    Maybe I'm not calling this correctly?

    foo = param.DataFrame(columns=3) results in:

    ---------------------------------------------------------------------------
    AttributeError                            Traceback (most recent call last)
    <ipython-input-2-526280bfed91> in <module>
          5 # class test(param.Parameterized):
          6 #     df = param.DataFrame(rows=3, columns=4)
    ----> 7 foo = param.DataFrame(columns=3)
    
    ~/ers/gitHub/param/master/param/param/__init__.py in __init__(self, rows, columns, ordered, **params)
       1313         self.columns = columns
       1314         self.ordered = ordered
    -> 1315         super(DataFrame,self).__init__(pdDFrame, allow_None=True, **params)
       1316         self._check_value(self.default)
       1317 
    
    ~/ers/gitHub/param/master/param/param/__init__.py in __init__(self, class_, default, instantiate, is_instance, **params)
       1150         self.is_instance = is_instance
       1151         super(ClassSelector,self).__init__(default=default,instantiate=instantiate,**params)
    -> 1152         self._check_value(default)
       1153 
       1154 
    
    ~/ers/gitHub/param/master/param/param/__init__.py in _check_value(self, val, obj)
       1348                 raise ValueError(msg.format(found=list(val.columns), expected=sorted(self.columns)))
       1349         else:
    -> 1350             self._length_bounds_check(self.columns, len(val.columns), 'Column')
       1351 
       1352         if self.ordered:
    
    AttributeError: 'NoneType' object has no attribute 'columns'
    

    And

    foo = param.DataFrame(rows=3)

    results in:

    ---------------------------------------------------------------------------
    TypeError                                 Traceback (most recent call last)
    <ipython-input-3-eff4207c7467> in <module>
          5 # class test(param.Parameterized):
          6 #     df = param.DataFrame(rows=3, columns=4)
    ----> 7 foo = param.DataFrame(rows=3)
    
    ~/ers/gitHub/param/master/param/param/__init__.py in __init__(self, rows, columns, ordered, **params)
       1313         self.columns = columns
       1314         self.ordered = ordered
    -> 1315         super(DataFrame,self).__init__(pdDFrame, allow_None=True, **params)
       1316         self._check_value(self.default)
       1317 
    
    ~/ers/gitHub/param/master/param/param/__init__.py in __init__(self, class_, default, instantiate, is_instance, **params)
       1150         self.is_instance = is_instance
       1151         super(ClassSelector,self).__init__(default=default,instantiate=instantiate,**params)
    -> 1152         self._check_value(default)
       1153 
       1154 
    
    ~/ers/gitHub/param/master/param/param/__init__.py in _check_value(self, val, obj)
       1356 
       1357         if self.rows is not None:
    -> 1358             self._length_bounds_check(self.rows, len(val), 'Row')
       1359 
       1360     def __set__(self,obj,val):
    
    TypeError: object of type 'NoneType' has no len()
    
    opened by kcpevey 18
  • JSON serialization and schema generation

    JSON serialization and schema generation

    This PR outlines another attempt at serializing/deserializing to JSON (for reference see #153 for earlier attempts at tackling this problem). The design used in this PR aims to try to keep things simpler but also adds the ability to generate JSON Schemas which should help with testing as well as specification of allowable parameter values (e.g this could be used to specify suitable widgets in panel).

    This PR is based off the ideas suggested in #382.

    TODO:

    • [ ] The main open problem is about finding the appropriate API and JSON (and schema) representation for entire parameterized objects (i.e including the class identity as well as all the parameters).
    opened by jlstevens 17
  • Added pprint function to parameterized.py

    Added pprint function to parameterized.py

    This PR adds something I've long wished for in param: sensible, short reprs that actually work. :-)

    Although I started implementing this in __repr__, I saw the note about repr needing to be fast and then decided against implementing it there once I realized what was required.

    Instead of changing __repr__, I've ended up making a more robust pprint function that can be used as follows:

    class Foo(param.Parameterized):
    
        a = param.Number(4, precedence=6)
    
        b = param.String('B', precedence=-9)
    
        c = param.Number(4, precedence=0)
    
        z = param.Number(4, precedence=0)
    
        def __init__(self, a, b, c=4, d=99, **kwargs):
            self.d = d
            super(Foo, self).__init__(a=a, b=b, c=c, **kwargs)
    
        def __repr__(self):
            return param.parameterized.pprint(self, {'d':self.d})
    

    First the positional arguments are shown as their appropriate values. Then modified keyword arguments are shown in the order they are declared in. Then the varargs (e.g *varargs) is shown (if present). Then if a keyword dictionary (i.e. **kwargs) is present, it is assumed that the modified parameters can then be listed in order of their precedence.

    Here are some examples:

    >>> Foo(1,'C')
    Foo(1, 'C')
    
    # Positional arguments always shown even if at default values
    >>> Foo(4,'B')  
    Foo(4,'B')
    
    # Keyword not shown if supplied at default value
    >>> Foo(4,'B', c=4) 
    Foo(4,'B')
    
    >>> Foo(4, 'B', c=5)
    Foo(4, 'B', c=5)
    
    # 'd' is not a parameter (supplied at the default value)
    >>> Foo(4,'B', c=5, d=99)   
    Foo(4, 'B', c=5)
    
    >>> Foo(4,'B', c=5, d=100)
     Foo(4,'B', c=5, d=100)
    
    >>>  Foo(4,'B', z=44, d=100)
     Foo(4,'B', z=44, d=100)
    
    >>>  Foo(4,'B', z=4, d=100)
    Foo(4, 'B', d=100)
    

    For comparison, here is an example of the default repr:

    >>>Foo(4,'B')
    Foo(a=4, b='B', c=4, name='Foo00456', z=4)
    

    My main concern with pprint is performance. It might be nice to cache some of the results of the introspection for performance reasons.

    EDIT: If you are happy with the addition of this function, I'll make sure to write a good number of unit tests for it.

    opened by jlstevens 17
  • Upgrade gmpy support to gmpy2

    Upgrade gmpy support to gmpy2

    gmpy is on longer maintained, in favor of gmpy2:

    GMPY and GMPY2 are C-coded Python extension modules that support fast multiple-precision arithmetic.

    GMPY only supports the GMP library and provides fast multiple-precision integer and rational arithmetic. The limited mpf type from GMP is also supported. GMPY is no longer being maintained.

    GMPY2 supports the GMP library for integer and rational arithmetic but GMPY2 adds support for multiple-precision real and complex arithmetic as provided by the MPFR and MPC libraries. GMPY2 is being actively developed.

    In https://github.com/holoviz/param/pull/658 (https://github.com/holoviz/param/pull/658/commits/c08ea2640a7e7ca2bb6bb34def1e99e80564e7e7) I attempted to simply replace all the gmpy imports by gmpy2 imports. On Linux there was a failing test and some warnings:

       __________ TestTimeDependentDynamic.test_time_hashing_rationals_gmpy2 __________
      
      self = <tests.API1.testtimedependent.TestTimeDependentDynamic testMethod=test_time_hashing_rationals_gmpy2>
      
          @pytest.mark.skipif(gmpy2 is None, reason="gmpy2 is not installed")
          def test_time_hashing_rationals_gmpy2(self):
              """
              Check that hashes of fractions and gmpy2 mpqs match for some
              reasonable rational numbers.
              """
              pi = "3.141592"
              hashfn = numbergen.Hash("test", input_count=1)
              self.assertEqual(hashfn(0.5), hashfn(gmpy2.mpq(0.5)))
      >       self.assertEqual(hashfn(pi), hashfn(gmpy2.mpq(3.141592)))
      E       AssertionError: 238769760 != 243050811
      
      tests/API1/testtimedependent.py:317: AssertionError
      ----------------------------- Captured stderr call -----------------------------
      WARNING:param.main: Casting type 'float' to Fraction.fraction
      WARNING:param.main: Casting type 'mpq' to Fraction.fraction
      WARNING:param.main: Casting type 'str' to Fraction.fraction
      WARNING:param.main: Casting type 'mpq' to Fraction.fraction
      ------------------------------ Captured log call -------------------------------
      WARNING  param.main:parameterized.py:2529 Casting type 'float' to Fraction.fraction
      WARNING  param.main:parameterized.py:2529 Casting type 'mpq' to Fraction.fraction
      WARNING  param.main:parameterized.py:2529 Casting type 'str' to Fraction.fraction
      WARNING  param.main:parameterized.py:2529 Casting type 'mpq' to Fraction.fraction
    

    Also at the time I tried it it wouldn't install on Linux/Python 3.11 and fail with:

            In file included from src/gmpy2.c:500:
            src/gmpy2.h:82:10: fatal error: mpfr.h: No such file or directory
               82 | #include <mpfr.h>
                  |          ^~~~~~~~
            compilation terminated.
            error: command '/usr/bin/gcc' failed with exit code 1
            [end of output]
    
    type-feature 
    opened by maximlt 0
  • param.Range does not check if values are numbers

    param.Range does not check if values are numbers

    Param doesn't complain when the bounds of a Range Parameter are set with weird values.

    import param
    
    class X(param.Parameterized):
        xlim = param.Range(bounds=('a', 'b'))
    
    x = X()
    

    This is because _valudate_bounds are not checking if the values are numbers, e.g., this is a valid comparison "a" < "b".

    https://github.com/holoviz/param/blob/ddcd5f36bcff1712f2c7fb984268a0ad6dc9649f/param/init.py#L2086-L2096

    type-bug 
    opened by Hoxbro 0
  • Improve DataFrame parameter to allow compatible instance types outside pandas (e.g. polars)

    Improve DataFrame parameter to allow compatible instance types outside pandas (e.g. polars)

    Request

    Please improve the DataFrame parameter so that other DataFrame types are supported, in particular polars.

    Motivation

    Polars is intentionally similar to Pandas, but aims to improve on performance. This is also the main reason for using it in combination with better arrows support. https://www.pola.rs/ Polars API Reference

    Discussion

    At the moment the DataFrame parameter is siloed into pandas, even though polars should be a drop in replacement without introducing bugs. Is there no better way of checking that a DataFrame is supplied (is default.__name__ not sufficient as a check)?

    Code Proposal

    A small change like this may be enough?

    https://github.com/holoviz/param/blob/ddcd5f36bcff1712f2c7fb984268a0ad6dc9649f/param/init.py#L209

                if 'polars' in sys.modules:
                    from polars import (
                        DataFrame as plDFrame, Series as plSeries
                    )
                    if isinstance(v, plDFrame):
                        params[k] = DataFrame(**kws)
                        continue
                    elif isinstance(v, plSeries):
                        params[k] = Series(**kws)
                        continue
                params[k] = Parameter(**kws)
    

    https://github.com/holoviz/param/blob/ddcd5f36bcff1712f2c7fb984268a0ad6dc9649f/param/init.py#L1518

        def __init__(self, default=None, rows=None, columns=None, ordered=None, **params):
            from pandas import DataFrame as pdDFrame
            from polars import DataFrame as plDFrame
            if isinstance(default, pdDFrame):
                dfClass = pdDFrame
            elif ifinstance(default, plDFrame):
                dfClass = plDFrame
            else:
                raise ValueError("Value supplied for DataFrame parameter is not a valid type of DataFrame.")
            self.rows = rows
            self.columns = columns
            self.ordered = ordered
            super(DataFrame,self).__init__(dfClass, default=default, **params)
            self._validate(self.default)
    

    I'm not advanced enough to wing the deserialize function. Is it as simple as checking for the type of the variable cls before deciding to return a pandas or polars DataFrame ?

    https://github.com/holoviz/param/blob/ddcd5f36bcff1712f2c7fb984268a0ad6dc9649f/param/init.py#L1576

        @classmethod
        def deserialize(cls, value):
            if value == 'null':
                return None
            if cls.__module__.split('.')[0] == 'pandas':
                from pandas import DataFrame as dFrame
            elif cls.__module__.split('.')[0] == 'polars':
                from polars import DataFrame as dFrame
            else:
                raise ValueError(
                    "Cannot Deserialise:  Value supplied for DataFrame parameter is not a valid type of DataFrame."
                )
            return dFrame(value)
    

    P.S.:

    The same applies for Series...

    opened by phi6ias 1
  • Support named and positional arguments on bound Parameterized methods

    Support named and positional arguments on bound Parameterized methods

    If you have a standalone function you can do

    @pn.depends(value1=object1.param.value, value2=object2.param.value)
    def view(value1, value2):
        ...
    

    But if its a class method you cannot have named or positional arguments.

    import panel as pn
    import param
    pn.extension()
    
    class Custom(param.Parameterized):
        value1 = param.String()
        value2 = param.String()
    
        @param.depends("value1", "value2")
        def view(self, value1, value2):
            return value1+value2
    
    custom=Custom()
    pn.Column(custom.view, pn.Param(custom)).servable()
    

    image

    TypeError: view() missing 2 required positional arguments: 'value1' and 'value2'
    

    Enabling this would make it easier to

    1. reason about which parameters are being using in the method.
    2. Use the values
    3. Refactor code between functional and class based
    4. write in a reactive style ala react.

    I would prefer this change would be implemented down to the param level.

    Additional Context

    If you added the posibility to provide a set_parameters function you would be able to develop in the React style of Idom and Solara.

    import panel as pn
    import param
    pn.extension()
    
    class Custom(param.Parameterized):
        value1 = param.String()
        value2 = param.String()
    
        @param.depends(value1="value1", value2="value2", react=True, watch=True)
        def view(self, value1, value2, set_parameters):
            ....
            set_parameters(value1=10)
    

    If you simplified we could have yet another api đŸ˜„

    @param.react(value1="value1", value2="value2", set_parameters=True, watch=True)
    def view(self, value1, value2, set_parameters):
        set_parameters(value1=10)
    
    API 
    opened by MarcSkovMadsen 0
  • Allow JSON serialization to work with json.dumps

    Allow JSON serialization to work with json.dumps

    Fixes #578

    The changes in #582 made it possible to round-trip serialize <-> deserialize within param.

    A completely valid way to deserialize is to have the serialized values created outside param like this:

    import json
    import param
    
    class User(param.Parameterized):
        A = param.Date(default=None)
    
    data = json.dumps({"A": None})    # gives: '{"A": null}' <- note that null is not a string
    User.param.deserialize_parameters(data)
    

    Which raised this error before these changes:

    Traceback (most recent call last):
      File "/home/shh/miniconda3/envs/holoviz/lib/python3.9/site-packages/IPython/core/interactiveshell.py", line 3378, in run_code
        exec(code_obj, self.user_global_ns, self.user_ns)
      File "/tmp/ipykernel_70470/342607310.py", line 8, in <module>
        User.param.deserialize_parameters(data)
      File "/home/shh/Development/holoviz/repos/param/param/parameterized.py", line 2121, in deserialize_parameters
        return serializer.deserialize_parameters(self_or_cls, serialization, subset=subset)
      File "/home/shh/Development/holoviz/repos/param/param/serializer.py", line 113, in deserialize_parameters
        deserialized = pobj.param[name].deserialize(value)
      File "/home/shh/Development/holoviz/repos/param/param/__init__.py", line 1954, in deserialize
        return dt.datetime.strptime(value, "%Y-%m-%dT%H:%M:%S.%f")
    TypeError: strptime() argument 1 must be str, not None
    
    opened by Hoxbro 0
  • concrete_descendents clobbers descendents

    concrete_descendents clobbers descendents

    ALL software version info

    param v1.12.2, Colab notebook

    Description of expected behavior and the observed behavior

    Simply put, classes with the same name get clobbered in get_concrete_descendents().

    I came across this bug when trying to run some unit tests with duplicated code (and class definitions) were in different files.

    Complete, minimal, self-contained example code that reproduces the issue

    import sys
    import param
    
    from param.parameterized import descendents
    
    print(param.__version__)
    
    class A(object):
      pass
    
    class B(A):
      pass
    
    b = B
    
    print(b in param.concrete_descendents(A).values())
    
    class B(A):
      pass
    
    print(b in param.concrete_descendents(A).values(), b in descendents(A))
    print(B in param.concrete_descendents(A).values(), B in descendents(A))
    print(issubclass(b, A), issubclass(b, A))
    

    Colab

    type-bug 
    opened by sdrobert 1
Releases(v1.12.2)
  • v1.12.2(Jun 24, 2022)

    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)
    Source code(tar.gz)
    Source code(zip)
  • v1.12.1(Mar 31, 2022)

    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)
    Source code(tar.gz)
    Source code(zip)
  • v1.12.0(Oct 21, 2021)

    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:

    • Added testing on Python 3.10 and on Mac OS X and removed slow PyPy/pandas/numpy tests (#548, #549, #526)
    • Docs/tests/build infrastructure improvements (#509, #521, #529, #530, #537, #538, #539, #547, #548, #555)

    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)
    Source code(tar.gz)
    Source code(zip)
  • v1.11.1(Jul 6, 2021)

    (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)
    Source code(tar.gz)
    Source code(zip)
  • v1.10.1(May 10, 2021)

    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)
    Source code(tar.gz)
    Source code(zip)
  • v1.9.3(Jan 26, 2020)

  • v1.9.2(Jan 23, 2020)

  • v1.9.1(Oct 8, 2019)

    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)
    Source code(tar.gz)
    Source code(zip)
  • v1.9.0(Apr 8, 2019)

    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:

    • Various bugfixes (#320, #323, #327, #329)
    • Other improvements (#315, #325)

    For more details, you can see a full list of changes since the previous release.

    Source code(tar.gz)
    Source code(zip)
  • v1.8.2(Feb 4, 2019)

  • v1.8.1(Oct 28, 2018)

  • v1.8.0(Oct 28, 2018)

    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.

    Source code(tar.gz)
    Source code(zip)
  • v1.7.0(Jun 28, 2018)

    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/pyviz/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.

    Source code(tar.gz)
    Source code(zip)
  • v1.6.1(Apr 25, 2018)

    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/pyviz/autover/pull/39)

    • Allow develop install to work when repository is dirty (https://github.com/pyviz/autover/pull/41)

    • Fixed failure to report dirty when commit count is 0 (https://github.com/pyviz/autover/pull/44)

    Source code(tar.gz)
    Source code(zip)
  • v1.6.0(Apr 5, 2018)

    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).
    Source code(tar.gz)
    Source code(zip)
  • v1.5.1(Apr 26, 2017)

    • 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.

    Source code(tar.gz)
    Source code(zip)
  • v1.5.0(Feb 27, 2017)

    • Added Range, Color, and Date parameters
    • Improved ObjectSelector error messages
    • Minor bugfixes

    A full list of changes since the previous release is available here.

    Source code(tar.gz)
    Source code(zip)
  • v1.4.2(Oct 14, 2016)

  • v1.4.1(Jul 12, 2016)

  • v1.4.0(Jul 11, 2016)

Owner
HoloViz
High-level tools to simplify visualization in Python
HoloViz
Lightweight data validation and adaptation Python library.

Valideer Lightweight data validation and adaptation library for Python. At a Glance: Supports both validation (check if a value is valid) and adaptati

Podio 258 Nov 22, 2022
An(other) implementation of JSON Schema for Python

jsonschema jsonschema is an implementation of JSON Schema for Python. >>> from jsonschema import validate >>> # A sample schema, like what we'd get f

Julian Berman 3.9k Nov 23, 2022
Lightweight, extensible data validation library for Python

Cerberus Cerberus is a lightweight and extensible data validation library for Python. >>> v = Validator({'name': {'type': 'string'}}) >>> v.validate({

eve 2.9k Nov 28, 2022
CONTRIBUTIONS ONLY: Voluptuous, despite the name, is a Python data validation library.

CONTRIBUTIONS ONLY What does this mean? I do not have time to fix issues myself. The only way fixes or new features will be added is by people submitt

Alec Thomas 1.8k Nov 12, 2022
Python Data Validation for Humansâ„¢.

validators Python data validation for Humans. Python has all kinds of data validation tools, but every one of them seems to require defining a schema

Konsta Vesterinen 658 Nov 23, 2022
A simple, fast, extensible python library for data validation.

Validr A simple, fast, extensible python library for data validation. Simple and readable schema 10X faster than jsonschema, 40X faster than schematic

kk 209 Sep 19, 2022
Typical: Fast, simple, & correct data-validation using Python 3 typing.

typical: Python's Typing Toolkit Introduction Typical is a library devoted to runtime analysis, inference, validation, and enforcement of Python types

Sean 164 Nov 9, 2022
Python Data Structures for Humansâ„¢.

Schematics Python Data Structures for Humansâ„¢. About Project documentation: https://schematics.readthedocs.io/en/latest/ Schematics is a Python librar

Schematics 2.5k Nov 19, 2022
Type-safe YAML parser and validator.

StrictYAML StrictYAML is a type-safe YAML parser that parses and validates a restricted subset of the YAML specification. Priorities: Beautiful API Re

Colm O'Connor 1.2k Nov 23, 2022
Smaller, easier, more powerful, and more reliable than make. An implementation of djb's redo.

redo - a recursive build system Smaller, easier, more powerful, and more reliable than make. This is an implementation of Daniel J. Bernstein's redo b

null 1.7k Nov 20, 2022
Image enhancing model for making a blurred image to be somehow clearer than before

This is a very small prject which helps in enhancing the images by taking a Input images. This project has many features like detcting the faces and enhaning the faces itself and also a feature which enhances the whole image

null 3 Dec 3, 2021
Milano is a tool for automating hyper-parameters search for your models on a backend of your choice.

Milano (This is a research project, not an official NVIDIA product.) Documentation https://nvidia.github.io/Milano Milano (Machine learning autotuner

NVIDIA Corporation 146 Nov 1, 2022
toldium is a modular, fast, reliable and customizable multiplatform bot library for your communities

toldium The easy multiplatform bot toldium is a modular, fast, reliable and customizable multiplatform bot library for your communities, from a commun

Stockdroid Fans 5 Nov 3, 2021
ChairBot is designed to be reliable, easy to use, and lightweight for every user, and easliy to code add-ons for ChairBot.

ChairBot is designed to be reliable, easy to use, and lightweight for every user, and easliy to code add-ons for ChairBot. Ready to see whats possible with ChairBot?

null 1 Nov 8, 2021
A simple bot that will help you in your learning and make it more fun.

hyperskill-SimpleChattyBot-python A simple bot that will help you in your learning and make it more fun. Syntax bot.py Stages Stage #1: Zuhura Bot we

null 1 Nov 9, 2021
Dome - Subdomain Enumeration Tool. Fast and reliable python script that makes active and/or passive scan to obtain subdomains and search for open ports.

DOME - A subdomain enumeration tool Check the Spanish Version Dome is a fast and reliable python script that makes active and/or passive scan to obtai

Vadi 307 Nov 19, 2022
MM1 and MMC Queue Simulation using python - Results and parameters in excel and csv files

implementation of MM1 and MMC Queue on randomly generated data and evaluate simulation results then compare with analytical results and draw a plot curve for them, simulate some integrals and compare results and run monte carlo algorithm with them

Mohamadreza Rezaei 1 Jan 19, 2022
WebApp Maker make web apps (Duh). It is open source and make with python and shell.

WebApp Maker make web apps (Duh). It is open source and make with python and shell. This app can take any website and turn it into an app. I highly recommend turning these few websites into webapps: - Krunker.io (Fps Game) - play.fancade.com (Minigame Arcade) - Your Own Website If You Have One Apart from that enjoy my app By 220735540 (a.k.a RP400)

null 2 Jan 9, 2022