Skip to content
Snippets Groups Projects

Config with __slots__ and validation

  • Clone with SSH
  • Clone with HTTPS
  • Embed
  • Share
    The snippet can be accessed without any authentication.
    Authored by Françoise Conil
    slots_sms_config_validators.py 3.50 KiB
    """
    https://docs.python.org/3.8/reference/datamodel.html#slots
    
    __slots__ are implemented at the class level by creating descriptors (Implementing Descriptors) for each variable name.
    """
    
    import collections
    from http import HTTPStatus
    import os
    from urllib import request
    from urllib.error import URLError
    
    
    # For validation
    ACCEPTED_FORMATS = ('json', 'csv', 'xml')
    
    class Config:
    
        __slots__ = ('name', 'mode', 'url', 'delay', 'format', 'maxitems')
    
        def __init__(self, defaults):
            # Initialisation
            self.name = os.environ.get(defaults['name'].envvar, defaults['name'].default)
            self.mode = os.environ.get(defaults['mode'].envvar, defaults['mode'].default)
            self.url = os.environ.get(defaults['url'].envvar, defaults['url'].default)
            self.delay = os.environ.get(defaults['delay'].envvar, defaults['delay'].default)
            self.format = os.environ.get(defaults['format'].envvar, defaults['format'].default)
            self.maxitems = os.environ.get(defaults['maxitems'].envvar, defaults['maxitems'].default)
    
        def valid_format(self):
            # Do we accept None value ?
            if self.format not in ACCEPTED_FORMATS:
                raise ValueError(f"Expected {self.format!r} to be one of {ACCEPTED_FORMATS!r}")
    
        def valid_url(self):
            # Do we accept None value ?
            try:
                response = request.urlopen(self.url)
            except URLError as e:
                # Avoid showing all stacktrace with URLError and OSError
                # https://docs.python.org/3.9/tutorial/errors.html#exception-chaining
                raise ValueError(f'Expected {self.url} should is triggering an error {e}') from None
            else:
                # What about moved content 301 (MOVED_PERMANENTLY) or 
                # cached content 304 (NOT_MODIFIED)
                if response.status != HTTPStatus.OK:
                    raise ValueError(f'Expected {self.url} should be a valid URL {response.status}')
    
    
    if __name__ == "__main__":
        # Using namedtuple to better manipulated defaults
        # https://docs.python.org/3.8/library/collections.html#collections.namedtuple
        # ---------------------------------------------------------------------------
        fparam = collections.namedtuple('FetcherParameters', ['name', 'envvar', 'description', 'default'])
    
        fetcher_defaults = {
                'name': fparam(name='name', envvar='HTTP_FETCHER_NAME', description='Name of the acquisition', default=None),
                'mode': fparam(name='mode', envvar='HTTP_FETCHER_MODE', description='http method', default='GET'),
                'url': fparam(name='url', envvar='HTTP_FETCHER_URL', description='URL to fetch', default=None),
                'delay': fparam(name='delay', envvar='HTTP_FETCHER_DELAY', description='Delay between requests in seconds', default=3600),
                'format': fparam(name='format', envvar='HTTP_FETCHER_FORMAT', description='File format', default='json'),
                'maxitems': fparam(name='maxitems', envvar='HTTP_FETCHER_MAXITEMS', description='Max number of fetches', default=-1)
                }
    
        print(f"-- vars(Config) = {vars(Config)}")
    
        c = Config(fetcher_defaults)
    
        print("-- After instanciation")
        for k in fetcher_defaults.keys():
            print(f"c.{k} = {getattr(c, k)}, ")
    
        c.format = 'xml'
        c.valid_format()
    
        print("-- After format change")
        for k in fetcher_defaults.keys():
            print(f"c.{k} = {getattr(c, k)}, ")
    
        c.url = 'https://www.twitterfountain.com/'
        #c.url = 'https://download.data.grandlyon.com/ws/ldata/velov.stations/all.json?maxfeatures=5&start=1'
        c.valid_url()
    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