Class Config with descriptor and special initialisation
The snippet can be accessed without any authentication.
Authored by
Françoise Conil
"""
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}")
Please register or sign in to comment