Skip to content
Snippets Groups Projects

Class Config with descriptor and special initialisation

  • Clone with SSH
  • Clone with HTTPS
  • Embed
  • Share
    The snippet can be accessed without any authentication.
    Authored by Françoise Conil
    descriptors_sms_config_with_init.py 3.96 KiB
    """
    https://docs.python.org/3.9/howto/descriptor.html#complete-practical-example
    
    In : type(c1).__dict__
    Out:
    mappingproxy({'__module__': '__main__',
                  'name': <__main__.ConfigParameter at 0x7efe927a12e0>,
                  'mode': <__main__.ConfigParameter at 0x7efe927a1940>,
                  'url': <__main__.ConfigParameter at 0x7efe927a1be0>,
                  'delay': <__main__.ConfigParameter at 0x7efe927a1190>,
                  'format': <__main__.ConfigParameter at 0x7efeaae23a60>,
                  'maxitems': <__main__.ConfigParameter at 0x7efeaad81400>,
                  '__init__': <function __main__.Config.__init__(self)>,
                  '__dict__': <attribute '__dict__' of 'Config' objects>,
                  '__weakref__': <attribute '__weakref__' of 'Config' objects>,
                  '__doc__': None})
    
    In : type(c1).__dict__['format']
    Out: <__main__.ConfigParameter at 0x7efeaae23a60>
    
    In : type(c1).__dict__['format'].__dict__
    Out:
    {'envvar': 'HTTP_FETCHER_FORMAT',
     'description': 'File format',
     'default': 'json',
     'public_name': 'format',
     'private_name': '_format'}
    
    Avec export HTTP_FETCHER_MODE="POST"
    
    In : c1.__dict__
    Out:
    {'_name': None,
     '_mode': 'POST',
     '_url': None,
     '_delay': 3600,
     '_format': 'xml',
     '_maxitems': -1}
    """
    
    import logging
    import os
    
    logging.basicConfig(level=logging.DEBUG)
    
    
    class ConfigParameter:
        def __init__(self, envvar=None, description=None, default=None):
            """
            Should we define positionnal parameters or use defaut values as
            None or one other.
            """
            self.envvar = envvar
            self.description = description
            self.default = default
    
        def __set_name__(self, owner, name):
            """Called at the time the owning class "owner" is created.
            The descriptor has been assigned to "name".
            https://docs.python.org/3/howto/descriptor.html#automatic-name-notification
    
            https://docs.python.org/3/reference/datamodel.html#object.__set_name__
            """
            self.public_name = name
            self.private_name = f"_{name}"
    
        def __get__(self, obj, objtype=None):
            """"""
            value = getattr(obj, self.private_name)
            logging.info("Accessing %r giving %r", self.public_name, value)
            return value
    
        def __set__(self, obj, value):
            logging.info("Updating %r to %r", self.public_name, value)
            setattr(obj, self.private_name, value)
    
        def set_initial_value(self, obj):
            logging.info("Set initial value for %r", self.public_name)
            self.__set__(obj, os.environ.get(self.envvar, self.default))
    
    
    class Config:
    
        name = ConfigParameter(
            envvar="HTTP_FETCHER_NAME", description="Name of the acquisition", default=None
        )
        mode = ConfigParameter(
            envvar="HTTP_FETCHER_MODE", description="http method", default="GET"
        )
        url = ConfigParameter(
            envvar="HTTP_FETCHER_URL", description="URL to fetch", default=None
        )
        delay = ConfigParameter(
            envvar="HTTP_FETCHER_DELAY",
            description="Delay between requests in seconds",
            default=3600,
        )
        # format is not a Python keyword,
        # https://docs.python.org/3.8/reference/lexical_analysis.html#keywords
        format = ConfigParameter(
            envvar="HTTP_FETCHER_FORMAT", description="File format", default="json"
        )
        maxitems = ConfigParameter(
            envvar="HTTP_FETCHER_MAXITEMS", description="Max number of fetches", default=-1
        )
    
        def __init__(self):
            for p in vars(type(self)):
                if isinstance(type(self).__dict__[p], ConfigParameter):
                    type(self).__dict__[p].set_initial_value(self)
    
    
    if __name__ == "__main__":
        logging.debug(f"vars(Config) = {vars(Config)}")
        logging.debug(f"vars(vars(Config)['mode']) = {vars(vars(Config)['mode'])}")
    
        c1 = Config()
    
        logging.debug(vars(c1))
        logging.debug(f"vars(Config)['mode'].__dict__ = {vars(Config)['mode'].__dict__}")
    
        c1.format = "xml"
    
        c2 = Config()
    
        c2.format = "csv"
    
        logging.debug(f"c1.format = {c1.format}, c2.format = {c2.format}")
    0% Loading or .
    You are about to add 0 people to the discussion. Proceed with caution.
    Finish editing this message first!
    Please register or to comment