Package: truconsts
truconstsVersion: 0.0.9truconstsis a constants management package for Python applications.It provides a base class namedBaseConstantswhich the user can subclass to achieve certain behaviours when accessing the class variables defined in the subclass. It also provides three classes that are meant for type-hinting,Immutable,YieldandCache.These three type-hinting classes do the following to the class variable:Immutable: The class variable annotated withImmutableis immutable. Its value cannot be changed, any assignment to the class variable will raise anAttributeError.Yield: The class variable annotated withYieldwill always return/yield a value whenever the class variable is accessed. You can assign a function,Cache: The class variable annotated withCachewill always cache the yielded/returned value from the first call to the function/generator/asynchronous generator (alias: async-gen). Subsequent accesses to the class variable will return the cached value.InstallationYou can use pip to install this packagepip install -U truconstsUsageIf you want immutable constantsfromtruconsts.constantsimportBaseConstantsfromtruconsts.annotationsimportImmutableclassMyConstants(BaseConstants):# annotate with `Immutable`MyImmutable:Immutable="Cannot Be Changed"try:MyConstants.MyImmutable="Let's change"exceptAttributeErroraserr:print(err)# prints `MyConstants.MyImmutable` cannot be mutatedIf you want cached constants'cached' constants refer to constants which are first 'gotten' through a function call and subsequent use of these constants need not be accessed through that function call.importtimeimportdatetimedefget_from_network():time.sleep(2)return'Going to cache'classMyConstants(BaseConstants):# annotate with `Cache`MyCache:Cache=get_from_networkstart=datetime.datetime.now()MyConstants.MyCacheend=datetime.datetime.now()print(f"Time taken to access the variable:{end-start}")# Time taken to access the variable: 0:00:02.000991start=datetime.datetime.now()MyConstants.MyCacheend=datetime.datetime.now()print(f"Time taken to access the variable after caching:{end-start}")# Time taken to access the variable after caching: 0:00:00.000999If you want 'yielding' constants'yielding' constants refer to constants (which are not 'really' constants in the strictest sense, but it's Python yeah...) to always generate a new value whenever you access them.importrandomdefgen():whileTrue:# this while loop is import# if you always want a random number# to be generate from this generatornum=random.randint(0,100)yieldnumclassMyConstants(BaseConstants):# annotate with `Yield`RANDOM_INT:Yield=genprint(MyConstants.RANDOM_INT)# 23print(MyConstants.RANDOM_INT)# 88If you want 'yielding' constants from an asynchronous generatorSame as the above, but now with asynchronous generator. It makes your generators run as if they are synchronous.asyncdefgen():i=1whilei:yieldii+=1asyncdefgetter():async_asend_gen=gen()whileTrue:num=awaitasync_asend_gen.asend(None)yieldnumclassMyConstants(BaseConstants):COUNT_UP:Yield=getter()print(MyConstants.COUNT_UP)# 1print(MyConstants.COUNT_UP)# 2print(MyConstants.COUNT_UP)# 3print(MyConstants.COUNT_UP)# 4If you want a mix of constants# Simple API, just subclass `BaseConstants`classConstants(BaseConstants):# `NUM` is an immutable `int`, i.e. Constants.NUM will always be 123NUM:Immutable[int]=123# No `Immutable` annotation implies Constants.STR is mutableSTR:str="Hello"# Constants.IMMU_FUNC will call `get_constant` function; the returned value is cached# and it is immutableIMMU_FUNC:Cache[Immutable]=get_constant# Order/Subscripting of annotation does not matterMUT_FUNC:Immutable[Cache]=get_constant# Only `Cache` annotation without `Immutable` means it is mutable even after# the returned value is cached after being called for the first timeJUST_CACHE:Cache[str]=get_constant# No annotation means it is neither `Cache` nor `Immutable`NO_ANNO="NO_ANNO"Finally, if you want to manage your own asynchronous generator but want the 'reference' to it to be immutableasyncdefgen():i=1whilei:stop=yieldiifstop==True:print("Someone asked me to stop!")returni+=1asyncdefgetter():async_asend_gen=gen()num=NonewhileTrue:i=awaitasync_asend_gen.asend(num)num=yieldiclassMyConstants(BaseConstants):INT:Immutable=getter()print(awaitMyConstants.INT.asend(None))# 1print(awaitMyConstants.INT.asend(None))# 2print(awaitMyConstants.INT.asend(None))# 3print(awaitMyConstants.INT.asend(None))# 4print(awaitMyConstants.INT.asend(True))# Someone asked me to stop!;# Raises `RuntimeError: async generator raised StopAsyncIteration``There are more examples in theexamplesfolder on Github.RoadmapDescriptionProgressCode SampleSubclassing e.g.Immutablesmake all subclass' class variables immutable[1]Able to define inner class in outer class definition and declare annotation through parameters passed into class call[1]Samples[1]# Future APIsclassMyConstants(BaseConstants):classFilePaths(Immutables,this_class_as=(Immutable,)):# All `TRAINING`, `TESTING` class variables will be `Immutable`.# The class variable `FilePaths` of `MyConstants`# will be immutable as well.TRAINING="."TESTING=".."VALIDATION="..."classYielders(Yields):# Same as above just that all class variables will be# `Yield` annotated but `Yielders` will be mutableFIRST=genContributingContributions are welcome!