truconsts


Nametruconsts JSON
Version 0.0.9 PyPI version JSON
download
home_page
SummarySimple, easy to use with intuitive APIs, for managing constants in your Python applications.
upload_time2023-06-27 18:28:28
maintainer
docs_urlNone
author
requires_python>=3.8
license
keywords truconsts truly constants constants
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # truconsts

[![Actions](https://img.shields.io/github/actions/workflow/status/jymchng/truconsts/test.yml?branch=main&logo=github&style=flat-square&maxAge=300)](https://github.com/jymchng/truconsts/actions)
[![Coverage](https://img.shields.io/codecov/c/gh/jymchng/truconsts/branch/main.svg?style=flat-square&maxAge=3600)](https://codecov.io/gh/jymchng/truconsts/)
[![License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square&maxAge=2678400)](https://choosealicense.com/licenses/mit/)
[![PyPI](https://img.shields.io/pypi/v/truconsts.svg?style=flat-square&maxAge=3600)](https://pypi.org/project/truconsts)
[![Wheel](https://img.shields.io/pypi/wheel/truconsts.svg?style=flat-square&maxAge=3600)](https://pypi.org/project/truconsts/#files)
[![Python Versions](https://img.shields.io/pypi/pyversions/truconsts.svg?style=flat-square&maxAge=600)](https://pypi.org/project/truconsts/#files)
[![Python Implementations](https://img.shields.io/pypi/implementation/truconsts.svg?style=flat-square&maxAge=600&label=impl)](https://pypi.org/project/truconsts/#files)
[![Source](https://img.shields.io/badge/source-GitHub-303030.svg?maxAge=2678400&style=flat-square)](https://github.com/jymchng/truconsts/)
[![Mirror](https://img.shields.io/badge/mirror-EMBL-009f4d?style=flat-square&maxAge=2678400)](https://git.embl.de/larralde/truconsts/)
[![Issues](https://img.shields.io/github/issues/jymchng/truconsts.svg?style=flat-square&maxAge=600)](https://github.com/jymchng/truconsts/issues)
[![Docs](https://img.shields.io/readthedocs/truconsts/latest?style=flat-square&maxAge=600)](https://truconsts.readthedocs.io)
[![Changelog](https://img.shields.io/badge/keep%20a-changelog-8A0707.svg?maxAge=2678400&style=flat-square)](https://github.com/jymchng/truconsts/blob/master/CHANGELOG.md)
[![Downloads](https://img.shields.io/badge/dynamic/json?style=flat-square&color=303f9f&maxAge=86400&label=downloads&query=%24.total_downloads&url=https%3A%2F%2Fapi.pepy.tech%2Fapi%2Fprojects%2Ftruconsts)](https://pepy.tech/project/truconsts)


<div align="center" height=1000, width=200>
<img src="assets/truconstscirlogo.png"  width="15%" height="30%"><br>
<img src="assets/truconsts_logo.png"  width="60%" height="30%">
</div>

## Version: 0.0.9

`truconsts` is a constants management package for Python applications.

It provides a base class named `BaseConstants` which 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`, `Yield` and `Cache`.

These three type-hinting classes do the following to the class variable:

`Immutable`: The class variable annotated with `Immutable` is immutable. Its value cannot be changed, any assignment to the class variable will raise an `AttributeError`.

`Yield`: The class variable annotated with `Yield` will always return/yield a value whenever the class variable is accessed. You can assign a function, 

`Cache`: The class variable annotated with `Cache` will 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.

# Installation

You can use pip to install this package
```
pip install -U truconsts
```

# Usage

## If you want immutable constants
```python
from truconsts.constants import BaseConstants
from truconsts.annotations import Immutable

class MyConstants(BaseConstants):
    # annotate with `Immutable`
    MyImmutable: Immutable = "Cannot Be Changed"
    
try:
    MyConstants.MyImmutable = "Let's change"
except AttributeError as err:
    print(err)
# prints `MyConstants.MyImmutable` cannot be mutated
```

## If 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.
```python
import time
import datetime

def get_from_network():
    time.sleep(2)
    return 'Going to cache'

class MyConstants(BaseConstants):
    # annotate with `Cache`
    MyCache: Cache = get_from_network
    
start = datetime.datetime.now()
MyConstants.MyCache
end = datetime.datetime.now()
print(f"Time taken to access the variable: {end-start}")
# Time taken to access the variable: 0:00:02.000991

start = datetime.datetime.now()
MyConstants.MyCache
end = 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.000999
```

## If 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.
```python
import random

def gen():
    while True: # this while loop is import 
        # if you always want a random number
        # to be generate from this generator
        num = random.randint(0, 100)
        yield num
    
class MyConstants(BaseConstants):
    # annotate with `Yield`
    RANDOM_INT: Yield = gen 
    
print(MyConstants.RANDOM_INT) # 23
print(MyConstants.RANDOM_INT) # 88
```

## If you want 'yielding' constants from an asynchronous generator
Same as the above, but now with asynchronous generator. It makes your generators run as if they are synchronous.
```python
async def gen():
    i = 1
    while i:
        yield i
        i += 1

async def getter():
    async_asend_gen = gen()
    while True:
        num = await async_asend_gen.asend(None)
        yield num
    
class MyConstants(BaseConstants):
    COUNT_UP: Yield = getter()
    
print(MyConstants.COUNT_UP) # 1
print(MyConstants.COUNT_UP) # 2
print(MyConstants.COUNT_UP) # 3
print(MyConstants.COUNT_UP) # 4
```

## If you want a mix of constants
```python
# Simple API, just subclass `BaseConstants`
class Constants(BaseConstants):
    # `NUM` is an immutable `int`, i.e. Constants.NUM will always be 123
    NUM: Immutable[int] = 123
    # No `Immutable` annotation implies Constants.STR is mutable
    STR: str = "Hello"
    # Constants.IMMU_FUNC will call `get_constant` function; the returned value is cached
    # and it is immutable
    IMMU_FUNC: Cache[Immutable] = get_constant
    # Order/Subscripting of annotation does not matter
    MUT_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 time
    JUST_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 immutable
```python
async def gen():
    i = 1
    while i:
        stop = yield i
        if stop == True:
            print("Someone asked me to stop!")
            return
        i += 1

async def getter():
    async_asend_gen = gen()
    num = None
    while True:
        i = await async_asend_gen.asend(num)
        num = yield i

class MyConstants(BaseConstants):
    INT: Immutable = getter()
    
print(await MyConstants.INT.asend(None)) # 1
print(await MyConstants.INT.asend(None)) # 2
print(await MyConstants.INT.asend(None)) # 3
print(await MyConstants.INT.asend(None)) # 4
print(await MyConstants.INT.asend(True)) # Someone asked me to stop!;
# Raises `RuntimeError: async generator raised StopAsyncIteration``
```
There are more examples in the `examples` folder on Github.

# Roadmap

|Description|Progress|Code Sample|
|:--|:--:|:--:|
|Subclassing e.g. `Immutables` make all subclass' class variables immutable|![](https://img.shields.io/badge/Status-UNCOMPLETED-red)|[1]|
|Able to define inner class in outer class definition and declare annotation through parameters passed into class call|![](https://img.shields.io/badge/Status-UNCOMPLETED-red)|[1]|

## Samples

### [1]
```python
# Future APIs

class MyConstants(BaseConstants):
    
    class FilePaths(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 = "..."
        
    class Yielders(Yields):
        # Same as above just that all class variables will be
        # `Yield` annotated but `Yielders` will be mutable
        FIRST = gen
```
# Contributing
Contributions are welcome!

            

Raw data

            {
    "_id": null,
    "home_page": "",
    "name": "truconsts",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.8",
    "maintainer_email": "",
    "keywords": "truconsts,truly constants,constants",
    "author": "",
    "author_email": "Jim Chng <jimchng@outlook.com>",
    "download_url": "https://files.pythonhosted.org/packages/15/8e/793a0bff4b805f26c327a799b3f647ffb41467c8c24323ae78b513a5b809/truconsts-0.0.9.tar.gz",
    "platform": null,
    "description": "# truconsts\r\n\r\n[![Actions](https://img.shields.io/github/actions/workflow/status/jymchng/truconsts/test.yml?branch=main&logo=github&style=flat-square&maxAge=300)](https://github.com/jymchng/truconsts/actions)\r\n[![Coverage](https://img.shields.io/codecov/c/gh/jymchng/truconsts/branch/main.svg?style=flat-square&maxAge=3600)](https://codecov.io/gh/jymchng/truconsts/)\r\n[![License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square&maxAge=2678400)](https://choosealicense.com/licenses/mit/)\r\n[![PyPI](https://img.shields.io/pypi/v/truconsts.svg?style=flat-square&maxAge=3600)](https://pypi.org/project/truconsts)\r\n[![Wheel](https://img.shields.io/pypi/wheel/truconsts.svg?style=flat-square&maxAge=3600)](https://pypi.org/project/truconsts/#files)\r\n[![Python Versions](https://img.shields.io/pypi/pyversions/truconsts.svg?style=flat-square&maxAge=600)](https://pypi.org/project/truconsts/#files)\r\n[![Python Implementations](https://img.shields.io/pypi/implementation/truconsts.svg?style=flat-square&maxAge=600&label=impl)](https://pypi.org/project/truconsts/#files)\r\n[![Source](https://img.shields.io/badge/source-GitHub-303030.svg?maxAge=2678400&style=flat-square)](https://github.com/jymchng/truconsts/)\r\n[![Mirror](https://img.shields.io/badge/mirror-EMBL-009f4d?style=flat-square&maxAge=2678400)](https://git.embl.de/larralde/truconsts/)\r\n[![Issues](https://img.shields.io/github/issues/jymchng/truconsts.svg?style=flat-square&maxAge=600)](https://github.com/jymchng/truconsts/issues)\r\n[![Docs](https://img.shields.io/readthedocs/truconsts/latest?style=flat-square&maxAge=600)](https://truconsts.readthedocs.io)\r\n[![Changelog](https://img.shields.io/badge/keep%20a-changelog-8A0707.svg?maxAge=2678400&style=flat-square)](https://github.com/jymchng/truconsts/blob/master/CHANGELOG.md)\r\n[![Downloads](https://img.shields.io/badge/dynamic/json?style=flat-square&color=303f9f&maxAge=86400&label=downloads&query=%24.total_downloads&url=https%3A%2F%2Fapi.pepy.tech%2Fapi%2Fprojects%2Ftruconsts)](https://pepy.tech/project/truconsts)\r\n\r\n\r\n<div align=\"center\" height=1000, width=200>\r\n<img src=\"assets/truconstscirlogo.png\"  width=\"15%\" height=\"30%\"><br>\r\n<img src=\"assets/truconsts_logo.png\"  width=\"60%\" height=\"30%\">\r\n</div>\r\n\r\n## Version: 0.0.9\r\n\r\n`truconsts` is a constants management package for Python applications.\r\n\r\nIt provides a base class named `BaseConstants` which 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`, `Yield` and `Cache`.\r\n\r\nThese three type-hinting classes do the following to the class variable:\r\n\r\n`Immutable`: The class variable annotated with `Immutable` is immutable. Its value cannot be changed, any assignment to the class variable will raise an `AttributeError`.\r\n\r\n`Yield`: The class variable annotated with `Yield` will always return/yield a value whenever the class variable is accessed. You can assign a function, \r\n\r\n`Cache`: The class variable annotated with `Cache` will 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.\r\n\r\n# Installation\r\n\r\nYou can use pip to install this package\r\n```\r\npip install -U truconsts\r\n```\r\n\r\n# Usage\r\n\r\n## If you want immutable constants\r\n```python\r\nfrom truconsts.constants import BaseConstants\r\nfrom truconsts.annotations import Immutable\r\n\r\nclass MyConstants(BaseConstants):\r\n    # annotate with `Immutable`\r\n    MyImmutable: Immutable = \"Cannot Be Changed\"\r\n    \r\ntry:\r\n    MyConstants.MyImmutable = \"Let's change\"\r\nexcept AttributeError as err:\r\n    print(err)\r\n# prints `MyConstants.MyImmutable` cannot be mutated\r\n```\r\n\r\n## If you want cached constants\r\n'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.\r\n```python\r\nimport time\r\nimport datetime\r\n\r\ndef get_from_network():\r\n    time.sleep(2)\r\n    return 'Going to cache'\r\n\r\nclass MyConstants(BaseConstants):\r\n    # annotate with `Cache`\r\n    MyCache: Cache = get_from_network\r\n    \r\nstart = datetime.datetime.now()\r\nMyConstants.MyCache\r\nend = datetime.datetime.now()\r\nprint(f\"Time taken to access the variable: {end-start}\")\r\n# Time taken to access the variable: 0:00:02.000991\r\n\r\nstart = datetime.datetime.now()\r\nMyConstants.MyCache\r\nend = datetime.datetime.now()\r\nprint(f\"Time taken to access the variable after caching: {end-start}\")\r\n# Time taken to access the variable after caching: 0:00:00.000999\r\n```\r\n\r\n## If you want 'yielding' constants\r\n'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.\r\n```python\r\nimport random\r\n\r\ndef gen():\r\n    while True: # this while loop is import \r\n        # if you always want a random number\r\n        # to be generate from this generator\r\n        num = random.randint(0, 100)\r\n        yield num\r\n    \r\nclass MyConstants(BaseConstants):\r\n    # annotate with `Yield`\r\n    RANDOM_INT: Yield = gen \r\n    \r\nprint(MyConstants.RANDOM_INT) # 23\r\nprint(MyConstants.RANDOM_INT) # 88\r\n```\r\n\r\n## If you want 'yielding' constants from an asynchronous generator\r\nSame as the above, but now with asynchronous generator. It makes your generators run as if they are synchronous.\r\n```python\r\nasync def gen():\r\n    i = 1\r\n    while i:\r\n        yield i\r\n        i += 1\r\n\r\nasync def getter():\r\n    async_asend_gen = gen()\r\n    while True:\r\n        num = await async_asend_gen.asend(None)\r\n        yield num\r\n    \r\nclass MyConstants(BaseConstants):\r\n    COUNT_UP: Yield = getter()\r\n    \r\nprint(MyConstants.COUNT_UP) # 1\r\nprint(MyConstants.COUNT_UP) # 2\r\nprint(MyConstants.COUNT_UP) # 3\r\nprint(MyConstants.COUNT_UP) # 4\r\n```\r\n\r\n## If you want a mix of constants\r\n```python\r\n# Simple API, just subclass `BaseConstants`\r\nclass Constants(BaseConstants):\r\n    # `NUM` is an immutable `int`, i.e. Constants.NUM will always be 123\r\n    NUM: Immutable[int] = 123\r\n    # No `Immutable` annotation implies Constants.STR is mutable\r\n    STR: str = \"Hello\"\r\n    # Constants.IMMU_FUNC will call `get_constant` function; the returned value is cached\r\n    # and it is immutable\r\n    IMMU_FUNC: Cache[Immutable] = get_constant\r\n    # Order/Subscripting of annotation does not matter\r\n    MUT_FUNC: Immutable[Cache] = get_constant\r\n    # Only `Cache` annotation without `Immutable` means it is mutable even after\r\n    # the returned value is cached after being called for the first time\r\n    JUST_CACHE: Cache[str] = get_constant\r\n    # No annotation means it is neither `Cache` nor `Immutable`\r\n    NO_ANNO = \"NO_ANNO\"\r\n```\r\n\r\n## Finally, if you want to manage your own asynchronous generator but want the 'reference' to it to be immutable\r\n```python\r\nasync def gen():\r\n    i = 1\r\n    while i:\r\n        stop = yield i\r\n        if stop == True:\r\n            print(\"Someone asked me to stop!\")\r\n            return\r\n        i += 1\r\n\r\nasync def getter():\r\n    async_asend_gen = gen()\r\n    num = None\r\n    while True:\r\n        i = await async_asend_gen.asend(num)\r\n        num = yield i\r\n\r\nclass MyConstants(BaseConstants):\r\n    INT: Immutable = getter()\r\n    \r\nprint(await MyConstants.INT.asend(None)) # 1\r\nprint(await MyConstants.INT.asend(None)) # 2\r\nprint(await MyConstants.INT.asend(None)) # 3\r\nprint(await MyConstants.INT.asend(None)) # 4\r\nprint(await MyConstants.INT.asend(True)) # Someone asked me to stop!;\r\n# Raises `RuntimeError: async generator raised StopAsyncIteration``\r\n```\r\nThere are more examples in the `examples` folder on Github.\r\n\r\n# Roadmap\r\n\r\n|Description|Progress|Code Sample|\r\n|:--|:--:|:--:|\r\n|Subclassing e.g. `Immutables` make all subclass' class variables immutable|![](https://img.shields.io/badge/Status-UNCOMPLETED-red)|[1]|\r\n|Able to define inner class in outer class definition and declare annotation through parameters passed into class call|![](https://img.shields.io/badge/Status-UNCOMPLETED-red)|[1]|\r\n\r\n## Samples\r\n\r\n### [1]\r\n```python\r\n# Future APIs\r\n\r\nclass MyConstants(BaseConstants):\r\n    \r\n    class FilePaths(Immutables, this_class_as=(Immutable,)):\r\n        # All `TRAINING`, `TESTING` class variables will be `Immutable`.\r\n        # The class variable `FilePaths` of `MyConstants`\r\n        # will be immutable as well.\r\n        TRAINING = \".\"\r\n        TESTING = \"..\"\r\n        VALIDATION = \"...\"\r\n        \r\n    class Yielders(Yields):\r\n        # Same as above just that all class variables will be\r\n        # `Yield` annotated but `Yielders` will be mutable\r\n        FIRST = gen\r\n```\r\n# Contributing\r\nContributions are welcome!\r\n",
    "bugtrack_url": null,
    "license": "",
    "summary": "Simple, easy to use with intuitive APIs, for managing constants in your Python applications.",
    "version": "0.0.9",
    "project_urls": null,
    "split_keywords": [
        "truconsts",
        "truly constants",
        "constants"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "158e793a0bff4b805f26c327a799b3f647ffb41467c8c24323ae78b513a5b809",
                "md5": "c8751f4f02c6c82eb752df2878a5f5db",
                "sha256": "dace782b928ba69e4a6c358dff71eede396f373afad05cb322d30d29904133ba"
            },
            "downloads": -1,
            "filename": "truconsts-0.0.9.tar.gz",
            "has_sig": false,
            "md5_digest": "c8751f4f02c6c82eb752df2878a5f5db",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8",
            "size": 53836,
            "upload_time": "2023-06-27T18:28:28",
            "upload_time_iso_8601": "2023-06-27T18:28:28.818479Z",
            "url": "https://files.pythonhosted.org/packages/15/8e/793a0bff4b805f26c327a799b3f647ffb41467c8c24323ae78b513a5b809/truconsts-0.0.9.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-06-27 18:28:28",
    "github": false,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "lcname": "truconsts"
}
        
Elapsed time: 1.62408s