pyconstclasses


Namepyconstclasses JSON
Version 1.0.5 PyPI version JSON
download
home_pageNone
SummaryPackage with const class decoratos and utility
upload_time2024-09-04 11:39:12
maintainerNone
docs_urlNone
authorSpectraL519
requires_python>=3.9
licenseMIT License Copyright (c) 2024 Jakub Musiał Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
keywords const const class const classes
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # PyConstClasses

[![tests](https://github.com/SpectraL519/pyconstclasses/actions/workflows/tests.yaml/badge.svg)](https://github.com/SpectraL519/pyconstclasses/actions/workflows/tests)
[![examples](https://github.com/SpectraL519/pyconstclasses/actions/workflows/examples.yaml/badge.svg)](https://github.com/SpectraL519/pyconstclasses/actions/workflows/examples)
[![format](https://github.com/SpectraL519/pyconstclasses/actions/workflows/format.yaml/badge.svg)](https://github.com/SpectraL519/pyconstclasses/actions/workflows/format)
[![coverage](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/SpectraL519/f6cec4c4c8e1733cfe45f807918a128a/raw/covbadge.json)]()

<br />

## Overview

`PyConstClasses` is a python package containing const class decorators and utility. It allows for the creation constant and static constant classes by utilizing the annotations of the class definition.

<br />
<br />

## Table of contents

* [Installation](#installation)
* [Tutorial](#tutorial)
    * [Basic usage](#basic-usage)
    * [Common parameters](#common-parameters)
    * [Decorator-specific parameters](#decorator-specific-parameters)
* [Examples](#examples)
* [Dev notes](#dev-notes)
    * [Environment setup](#environment-setup)
    * [Building](#building)
    * [Testing](#testing)
    * [Coverage](#coverage)
    * [Formatting](#formatting)
* [Licence](#licence)

<br />
<br />

## Installation

To install the PyConstClasses package in your python environment run:
```shell
pip install pyconstclasses
```
or
```shell
python -m pip install pyconstclasses
```

<br />
<br />

## Tutorial

After installing the package, you have to import it to your python program:
```python
import constclasses as cc
```

### Basic usage

The core of the PyConstClasses package are the `const_class` and `static_const_class` decorators. Both of these decorators override the default behaviour of the `__setattr__` magic method for the decorated class so that it thors `cc.ConstError` when trying to modify the constant attribute of an instance.

* The `const_class` decorator allows you to define a class structure and create constant instances of the defined class:

    ```python
    # const_class_basic.py

    @cc.const_class
    class Person:
        first_name: str
        last_name: str

        def __repr__(self) -> str:
            return f"{self.first_name} {self.last_name}"


    if __name__ == "__main__":
        john = Person("John", "Doe")
        print(f"{john = }")

        try:
            john.first_name = "Bob"
        except cc.ConstError as err:
            print(f"Error: {err}")

        try:
            john.last_name = "Smith"
        except cc.ConstError as err:
            print(f"Error: {err}")
    ```

    This program will produce the following output:
    ```
    john = John Doe
    Error: Cannot modify const attribute `first_name` of class `Person`
    Error: Cannot modify const attribute `last_name` of class `Person`
    ```

    The `const_class` decorators also provides the `new` method which allows for the creationg of new instances of the class based on an existing instance with the option to modify individual fields:

    ```python
    # const_class_new.py

    @cc.const_class(with_kwargs=True)
    class PersonKwargs:
        first_name: str
        last_name: str
        age: int

        def __repr__(self) -> str:
            return f"(kwargs) {self.first_name} {self.last_name} [age: {self.age}]"


    @cc.const_class(with_kwargs=False)
    class PersonArgs:
        first_name: str
        last_name: str
        age: int

        def __repr__(self) -> str:
            return f"(args) {self.first_name} {self.last_name} [age: {self.age}]"


    if __name__ == "__main__":
        john = PersonKwargs(first_name="John", last_name="Doe", age=21)
        print(f"{john = }")

        john_aged = john.new(age=22)
        print(f"{john_aged = }")

        john = PersonArgs("John", "Doe", 21)
        print(f"{john = }")

        john_aged = john.new(age=22)
        print(f"{john_aged = }")
    ```

    This program will produce the following output:
    ```
    john = (kwargs) John Doe [age: 21]
    john_aged = (kwargs) John Doe [age: 22]
    john = (args) John Doe [age: 21]
    john_aged = (args) John Doe [age: 22]
    ```

* The `static_const_class` deacorator allows you to define a pseudo-static resource with const members (it creates an instance of the decorated class):

    ```python
    # static_const_class_basic.py

    @cc.static_const_class
    class ProjectConfiguration:
        name: str = "MyProject"
        version: str = "alpha"

        def __repr__(self):
            return f"Project: {self.name}\nVersion: {self.version}"


    if __name__ == "__main__":
        print(f"Project configuration:\n{ProjectConfiguration}")

        try:
            ProjectConfiguration.name = "NewProjectName"
        except cc.ConstError as err:
            print(f"Error: {err}")

        try:
            ProjectConfiguration.version = "beta"
        except cc.ConstError as err:
            print(f"Error: {err}")
    ```

    This program will produce the following output:
    ```
    Project configuration:
    Project: MyProject
    Version: alpha
    Error: Cannot modify const attribute `name` of class `ProjectConfiguration`
    Error: Cannot modify const attribute `version` of class `ProjectConfiguration`
    ```

    Although the `static_const_class` decorator prevents "standard" class instantiation, you can create mutable instances of such classes:

    ```python
    @cc.static_const_class
    class DatabaseConfiguration:
        host: str = "localhost"
        port: int = 5432
        username: str = "admin"
        password: str = "secret"

        def __repr__(self):
            return (
                f"DatabaseConfiguration:\n"
                f"Host: {self.host}\n"
                f"Port: {self.port}\n"
                f"Username: {self.username}\n"
                f"Password: {self.password}"
            )


    if __name__ == "__main__":
        print(f"Database configuration:\n{DatabaseConfiguration}")

        try:
            DatabaseConfiguration.host = "remotehost"
        except cc.ConstError as err:
            print(f"Error: {err}")

        try:
            DatabaseConfiguration.port = 3306
        except cc.ConstError as err:
            print(f"Error: {err}")

        # Create a mutable instance for testing or development
        mutable_config = cc.mutable_instance(DatabaseConfiguration)
        mutable_config.host = "testhost"
        mutable_config.username = "testuser"
        mutable_config.password = "testpassword"

        print("\nMutable configuration for testing:")
        print(mutable_config)
    ```

> [!IMPORTANT]
> In the current version of the package the constant attributes have to be defined using annotations, i.e. the `member: type (= value)` syntax of the class member declaration is required

<br />

### Common parameters

Both const decorators - `const_class` and `static_const_class` - have the following parameters:

* `with_strict_types: bool`

    If this parameter's value is set to
    * `False` - the decorators will use the `attribute_type(given_value)` conversion, so as long as the given value's type is convertible to the desired type, the decorators will not raise any errors.
    * `True` - the decorators will perform an `isinstance(given_value, attribute_type)` check, the failure of which will result in raising a `TypeError`

    Example:
    ```python
    # common_with_strict_types.py

    @cc.const_class
    class Person:
        first_name: str
        last_name: str
        age: int

        def __repr__(self) -> str:
            return f"{self.first_name} {self.last_name} [age: {self.age}]"

    @cc.const_class(with_strict_types=True)
    class PersonStrictTypes:
        first_name: str
        last_name: str
        age: int

        def __repr__(self) -> str:
            return f"{self.first_name} {self.last_name} [age: {self.age}]"


    if __name__ == "__main__":
        john = Person("John", "Doe", 21.5)
        print(john)

        try:
            # invalid as 21.5 is not an instance of int
            john_strict = PersonStrictTypes("John", "Doe", 21.5)
        except TypeError as err:
            print(f"Error:\n{err}")

        john_strict = PersonStrictTypes("John", "Doe", 21)
        print(john_strict)
    ```

    This program will produce the following output:
    ```
    John Doe [age: 21]
    Error:
    Attribute value does not match the declared type:
            attribute: age, declared type: <class 'int'>, actual type: <class 'float'>
    John Doe [age: 21]
    ```

* `include: set[str]` and `exclude: set[str]`

    These parameters are used to define which class attributes are supposed to be treated as constant. If they are not set (or explicitly set to `None`) all attributes will be treaded as constant.

    Example:
    ```python
    # common_include.py

    @cc.const_class(include=["first_name", "last_name"])
    class Person:
        first_name: str
        last_name: str
        age: int

        def __repr__(self) -> str:
            return f"{self.first_name} {self.last_name} [age: {self.age}]"


    if __name__ == "__main__":
        john = Person("John", "Doe", 21)
        print(f"{john = }")

        try:
            john.first_name = "Bob"
        except cc.ConstError as err:
            print(f"Error: {err}")

        try:
            john.last_name = "Smith"
        except cc.ConstError as err:
            print(f"Error: {err}")

        # valid modification as the `age` parameter is not in the include set
        john.age = 22
        print(f"{john = }")
    ```

    This program will produce the followig output:
    ```
    john = John Doe [age: 21]
    Error: Cannot modify const attribute `first_name` of class `Person`
    Error: Cannot modify const attribute `last_name` of class `Person`
    john = John Doe [age: 22]
    ```

    The same can be achieved using the `exclude` parameter:

    Example:
    ```python
    # common_exclude.py

    @cc.const_class(exclude=["age"])
    class Person:
        first_name: str
        last_name: str
        age: int

        def __repr__(self) -> str:
            return f"{self.first_name} {self.last_name} [age: {self.age}]"
    ```

    The class defined in this example has the behaviour equivalent to the earlier `include` example.

> [!IMPORTANT]
> Simultaneous usage of the `incldue` and `exclude` parameters will result in raising a configuration error.

<br />

### Decorator-specific parameters

> [!NOTE]
> In the current version of the package only the `const_class` decorator has it's own specific parameters.

* `with_kwargs: bool`

    By default the `const_class` decorator adds a constructor which uses positional arguments to create a constant instance of the class. However if this parameter is set to `True`, the decorator will use the keyword arguments for this purpose.

    Example:
    ```python
    # const_class_with_kwargs.py

    @cc.const_class
    class PersonArgs:
        first_name: str
        last_name: str

        def __repr__(self) -> str:
            return f"{self.first_name} {self.last_name}"


    @cc.const_class(with_kwargs=True)
    class PersonKwargs:
        first_name: str
        last_name: str

        def __repr__(self) -> str:
            return f"{self.first_name} {self.last_name}"


    if __name__ == "__main__":
        john_args = PersonArgs("John", "Doe")
        print(f"{john_args = }")

        try:
            john_args = PersonArgs(first_name="John", last_name="Doe")
        except cc.InitializationError as err:
            print(f"Error: {err}")

        john_kwargs = PersonKwargs(first_name="John", last_name="Doe")
        print(f"{john_kwargs = }")
    ```

    This program will produce the following output:
    ```
    john_args = John Doe
    Error: Invalid number of arguments: expected 2 - got 0
    john_kwargs = John Doe
    ```

* `inherit_constructor: bool`

    By default the `const_class` decorator defines a constructor which manually assigns values to attributes. However if this parameter is set to `True` the class will be initialized using the user defined `__init__` function of the decorated class.

    Example:
    ```python
    # const_class_inherit_constructor.py

    @cc.static_const_class
    class ProjectConfiguration:
        name: str = "MyProject"
        version: str = "alpha"

        def __repr__(self):
            return f"Project: {self.name}\nVersion: {self.version}"


    if __name__ == "__main__":
        print(f"Project configuration:\n{ProjectConfiguration}")

        try:
            ProjectConfiguration.name = "NewProjectName"
        except cc.ConstError as err:
            print(f"Error: {err}")

        try:
            ProjectConfiguration.version = "beta"
        except cc.ConstError as err:
            print(f"Error: {err}")
    ```

    This program will produce the following output:
    ```
    john = John Doe
    Error: Cannot modify const attribute `first_name` of class `Person`
    Error: Cannot modify const attribute `last_name` of class `Person`
    ```

<br />
<br />

## Examples

The project examples shown in the [Tutorial](#tutorial) section can be found in the `examples` directory.

To run the example programs you need to install the PyConstClasses package into your python environment. You can install it via `pip` of using a local distribution build (the process is described in the [Dev notes](#dev-notes) section).

<br />
<br />

## Dev notes

### Environment setup:

To be able to build or test the project create a python virtual environment

```shell
python -m venv cc_venv
source cc_venv/bin/activate
pip install -r requirements-dev.txt
```

> [!NOTE]
> If any package listed in `requirements-dev.txt` is no longer required or if there is a new required package, update the requirements file using: `pip freeze > requirements-dev.txt`

### Building

To build the package, run:
```shell
python -m build
```

This will generate the `dist` directory with the `.whl` file. To locally test if the distribution is correct, you can run:
```shell
pip install dist/pyconstclasses-<version>-py3-none-any.whl --force-reinstall
```

> [!NOTE]
> To test the package build locally it is recommended to use a clean virtual environment.

### Testing:

The project uses `pytest` and `tox` for testing purposes.
* To run the tests for the current python interpreter run: `pytest -v`
* To run tests for all supported python versions run: `tox`

### Coverage

To generate a test coverage report you can run `tox` which will automatically generate `json` and `xml` reports (the types of coverage reports can be adjusted in `tox.ini`).

You can also generate the coverage reports manually with `pytest`, e.g.:
```shell
pytest -v --cov=constclasses --cov-report=xml --cov-report=html
```

> [!NOTE]
> When testing the project or generating coverate reports, python (or it's packages) will generate additional files (cache file, etc.). To easily clean those files from the working directory run `./scripts/cleanup.sh`

### Formatting:

The project uses `black` and `isort` for formatting purposes. To format the source code use the prepared script:
```shell
./scripts/format.sh
```
You can also use the `black` and `isort` packages directly, e.g.
```shell
python -m <black/isort> <path> (--check)
```

<br />
<br />

## Licence

The `PyConstClasses` project uses the [MIT Licence](https://opensource.org/license/mit/)

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "pyconstclasses",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.9",
    "maintainer_email": null,
    "keywords": "const, const class, const classes",
    "author": "SpectraL519",
    "author_email": null,
    "download_url": "https://files.pythonhosted.org/packages/f7/ca/2da1277ee562b28890e9bf838740bd388ca841704129015ce5493e3aeef0/pyconstclasses-1.0.5.tar.gz",
    "platform": null,
    "description": "# PyConstClasses\n\n[![tests](https://github.com/SpectraL519/pyconstclasses/actions/workflows/tests.yaml/badge.svg)](https://github.com/SpectraL519/pyconstclasses/actions/workflows/tests)\n[![examples](https://github.com/SpectraL519/pyconstclasses/actions/workflows/examples.yaml/badge.svg)](https://github.com/SpectraL519/pyconstclasses/actions/workflows/examples)\n[![format](https://github.com/SpectraL519/pyconstclasses/actions/workflows/format.yaml/badge.svg)](https://github.com/SpectraL519/pyconstclasses/actions/workflows/format)\n[![coverage](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/SpectraL519/f6cec4c4c8e1733cfe45f807918a128a/raw/covbadge.json)]()\n\n<br />\n\n## Overview\n\n`PyConstClasses` is a python package containing const class decorators and utility. It allows for the creation constant and static constant classes by utilizing the annotations of the class definition.\n\n<br />\n<br />\n\n## Table of contents\n\n* [Installation](#installation)\n* [Tutorial](#tutorial)\n    * [Basic usage](#basic-usage)\n    * [Common parameters](#common-parameters)\n    * [Decorator-specific parameters](#decorator-specific-parameters)\n* [Examples](#examples)\n* [Dev notes](#dev-notes)\n    * [Environment setup](#environment-setup)\n    * [Building](#building)\n    * [Testing](#testing)\n    * [Coverage](#coverage)\n    * [Formatting](#formatting)\n* [Licence](#licence)\n\n<br />\n<br />\n\n## Installation\n\nTo install the PyConstClasses package in your python environment run:\n```shell\npip install pyconstclasses\n```\nor\n```shell\npython -m pip install pyconstclasses\n```\n\n<br />\n<br />\n\n## Tutorial\n\nAfter installing the package, you have to import it to your python program:\n```python\nimport constclasses as cc\n```\n\n### Basic usage\n\nThe core of the PyConstClasses package are the `const_class` and `static_const_class` decorators. Both of these decorators override the default behaviour of the `__setattr__` magic method for the decorated class so that it thors `cc.ConstError` when trying to modify the constant attribute of an instance.\n\n* The `const_class` decorator allows you to define a class structure and create constant instances of the defined class:\n\n    ```python\n    # const_class_basic.py\n\n    @cc.const_class\n    class Person:\n        first_name: str\n        last_name: str\n\n        def __repr__(self) -> str:\n            return f\"{self.first_name} {self.last_name}\"\n\n\n    if __name__ == \"__main__\":\n        john = Person(\"John\", \"Doe\")\n        print(f\"{john = }\")\n\n        try:\n            john.first_name = \"Bob\"\n        except cc.ConstError as err:\n            print(f\"Error: {err}\")\n\n        try:\n            john.last_name = \"Smith\"\n        except cc.ConstError as err:\n            print(f\"Error: {err}\")\n    ```\n\n    This program will produce the following output:\n    ```\n    john = John Doe\n    Error: Cannot modify const attribute `first_name` of class `Person`\n    Error: Cannot modify const attribute `last_name` of class `Person`\n    ```\n\n    The `const_class` decorators also provides the `new` method which allows for the creationg of new instances of the class based on an existing instance with the option to modify individual fields:\n\n    ```python\n    # const_class_new.py\n\n    @cc.const_class(with_kwargs=True)\n    class PersonKwargs:\n        first_name: str\n        last_name: str\n        age: int\n\n        def __repr__(self) -> str:\n            return f\"(kwargs) {self.first_name} {self.last_name} [age: {self.age}]\"\n\n\n    @cc.const_class(with_kwargs=False)\n    class PersonArgs:\n        first_name: str\n        last_name: str\n        age: int\n\n        def __repr__(self) -> str:\n            return f\"(args) {self.first_name} {self.last_name} [age: {self.age}]\"\n\n\n    if __name__ == \"__main__\":\n        john = PersonKwargs(first_name=\"John\", last_name=\"Doe\", age=21)\n        print(f\"{john = }\")\n\n        john_aged = john.new(age=22)\n        print(f\"{john_aged = }\")\n\n        john = PersonArgs(\"John\", \"Doe\", 21)\n        print(f\"{john = }\")\n\n        john_aged = john.new(age=22)\n        print(f\"{john_aged = }\")\n    ```\n\n    This program will produce the following output:\n    ```\n    john = (kwargs) John Doe [age: 21]\n    john_aged = (kwargs) John Doe [age: 22]\n    john = (args) John Doe [age: 21]\n    john_aged = (args) John Doe [age: 22]\n    ```\n\n* The `static_const_class` deacorator allows you to define a pseudo-static resource with const members (it creates an instance of the decorated class):\n\n    ```python\n    # static_const_class_basic.py\n\n    @cc.static_const_class\n    class ProjectConfiguration:\n        name: str = \"MyProject\"\n        version: str = \"alpha\"\n\n        def __repr__(self):\n            return f\"Project: {self.name}\\nVersion: {self.version}\"\n\n\n    if __name__ == \"__main__\":\n        print(f\"Project configuration:\\n{ProjectConfiguration}\")\n\n        try:\n            ProjectConfiguration.name = \"NewProjectName\"\n        except cc.ConstError as err:\n            print(f\"Error: {err}\")\n\n        try:\n            ProjectConfiguration.version = \"beta\"\n        except cc.ConstError as err:\n            print(f\"Error: {err}\")\n    ```\n\n    This program will produce the following output:\n    ```\n    Project configuration:\n    Project: MyProject\n    Version: alpha\n    Error: Cannot modify const attribute `name` of class `ProjectConfiguration`\n    Error: Cannot modify const attribute `version` of class `ProjectConfiguration`\n    ```\n\n    Although the `static_const_class` decorator prevents \"standard\" class instantiation, you can create mutable instances of such classes:\n\n    ```python\n    @cc.static_const_class\n    class DatabaseConfiguration:\n        host: str = \"localhost\"\n        port: int = 5432\n        username: str = \"admin\"\n        password: str = \"secret\"\n\n        def __repr__(self):\n            return (\n                f\"DatabaseConfiguration:\\n\"\n                f\"Host: {self.host}\\n\"\n                f\"Port: {self.port}\\n\"\n                f\"Username: {self.username}\\n\"\n                f\"Password: {self.password}\"\n            )\n\n\n    if __name__ == \"__main__\":\n        print(f\"Database configuration:\\n{DatabaseConfiguration}\")\n\n        try:\n            DatabaseConfiguration.host = \"remotehost\"\n        except cc.ConstError as err:\n            print(f\"Error: {err}\")\n\n        try:\n            DatabaseConfiguration.port = 3306\n        except cc.ConstError as err:\n            print(f\"Error: {err}\")\n\n        # Create a mutable instance for testing or development\n        mutable_config = cc.mutable_instance(DatabaseConfiguration)\n        mutable_config.host = \"testhost\"\n        mutable_config.username = \"testuser\"\n        mutable_config.password = \"testpassword\"\n\n        print(\"\\nMutable configuration for testing:\")\n        print(mutable_config)\n    ```\n\n> [!IMPORTANT]\n> In the current version of the package the constant attributes have to be defined using annotations, i.e. the `member: type (= value)` syntax of the class member declaration is required\n\n<br />\n\n### Common parameters\n\nBoth const decorators - `const_class` and `static_const_class` - have the following parameters:\n\n* `with_strict_types: bool`\n\n    If this parameter's value is set to\n    * `False` - the decorators will use the `attribute_type(given_value)` conversion, so as long as the given value's type is convertible to the desired type, the decorators will not raise any errors.\n    * `True` - the decorators will perform an `isinstance(given_value, attribute_type)` check, the failure of which will result in raising a `TypeError`\n\n    Example:\n    ```python\n    # common_with_strict_types.py\n\n    @cc.const_class\n    class Person:\n        first_name: str\n        last_name: str\n        age: int\n\n        def __repr__(self) -> str:\n            return f\"{self.first_name} {self.last_name} [age: {self.age}]\"\n\n    @cc.const_class(with_strict_types=True)\n    class PersonStrictTypes:\n        first_name: str\n        last_name: str\n        age: int\n\n        def __repr__(self) -> str:\n            return f\"{self.first_name} {self.last_name} [age: {self.age}]\"\n\n\n    if __name__ == \"__main__\":\n        john = Person(\"John\", \"Doe\", 21.5)\n        print(john)\n\n        try:\n            # invalid as 21.5 is not an instance of int\n            john_strict = PersonStrictTypes(\"John\", \"Doe\", 21.5)\n        except TypeError as err:\n            print(f\"Error:\\n{err}\")\n\n        john_strict = PersonStrictTypes(\"John\", \"Doe\", 21)\n        print(john_strict)\n    ```\n\n    This program will produce the following output:\n    ```\n    John Doe [age: 21]\n    Error:\n    Attribute value does not match the declared type:\n            attribute: age, declared type: <class 'int'>, actual type: <class 'float'>\n    John Doe [age: 21]\n    ```\n\n* `include: set[str]` and `exclude: set[str]`\n\n    These parameters are used to define which class attributes are supposed to be treated as constant. If they are not set (or explicitly set to `None`) all attributes will be treaded as constant.\n\n    Example:\n    ```python\n    # common_include.py\n\n    @cc.const_class(include=[\"first_name\", \"last_name\"])\n    class Person:\n        first_name: str\n        last_name: str\n        age: int\n\n        def __repr__(self) -> str:\n            return f\"{self.first_name} {self.last_name} [age: {self.age}]\"\n\n\n    if __name__ == \"__main__\":\n        john = Person(\"John\", \"Doe\", 21)\n        print(f\"{john = }\")\n\n        try:\n            john.first_name = \"Bob\"\n        except cc.ConstError as err:\n            print(f\"Error: {err}\")\n\n        try:\n            john.last_name = \"Smith\"\n        except cc.ConstError as err:\n            print(f\"Error: {err}\")\n\n        # valid modification as the `age` parameter is not in the include set\n        john.age = 22\n        print(f\"{john = }\")\n    ```\n\n    This program will produce the followig output:\n    ```\n    john = John Doe [age: 21]\n    Error: Cannot modify const attribute `first_name` of class `Person`\n    Error: Cannot modify const attribute `last_name` of class `Person`\n    john = John Doe [age: 22]\n    ```\n\n    The same can be achieved using the `exclude` parameter:\n\n    Example:\n    ```python\n    # common_exclude.py\n\n    @cc.const_class(exclude=[\"age\"])\n    class Person:\n        first_name: str\n        last_name: str\n        age: int\n\n        def __repr__(self) -> str:\n            return f\"{self.first_name} {self.last_name} [age: {self.age}]\"\n    ```\n\n    The class defined in this example has the behaviour equivalent to the earlier `include` example.\n\n> [!IMPORTANT]\n> Simultaneous usage of the `incldue` and `exclude` parameters will result in raising a configuration error.\n\n<br />\n\n### Decorator-specific parameters\n\n> [!NOTE]\n> In the current version of the package only the `const_class` decorator has it's own specific parameters.\n\n* `with_kwargs: bool`\n\n    By default the `const_class` decorator adds a constructor which uses positional arguments to create a constant instance of the class. However if this parameter is set to `True`, the decorator will use the keyword arguments for this purpose.\n\n    Example:\n    ```python\n    # const_class_with_kwargs.py\n\n    @cc.const_class\n    class PersonArgs:\n        first_name: str\n        last_name: str\n\n        def __repr__(self) -> str:\n            return f\"{self.first_name} {self.last_name}\"\n\n\n    @cc.const_class(with_kwargs=True)\n    class PersonKwargs:\n        first_name: str\n        last_name: str\n\n        def __repr__(self) -> str:\n            return f\"{self.first_name} {self.last_name}\"\n\n\n    if __name__ == \"__main__\":\n        john_args = PersonArgs(\"John\", \"Doe\")\n        print(f\"{john_args = }\")\n\n        try:\n            john_args = PersonArgs(first_name=\"John\", last_name=\"Doe\")\n        except cc.InitializationError as err:\n            print(f\"Error: {err}\")\n\n        john_kwargs = PersonKwargs(first_name=\"John\", last_name=\"Doe\")\n        print(f\"{john_kwargs = }\")\n    ```\n\n    This program will produce the following output:\n    ```\n    john_args = John Doe\n    Error: Invalid number of arguments: expected 2 - got 0\n    john_kwargs = John Doe\n    ```\n\n* `inherit_constructor: bool`\n\n    By default the `const_class` decorator defines a constructor which manually assigns values to attributes. However if this parameter is set to `True` the class will be initialized using the user defined `__init__` function of the decorated class.\n\n    Example:\n    ```python\n    # const_class_inherit_constructor.py\n\n    @cc.static_const_class\n    class ProjectConfiguration:\n        name: str = \"MyProject\"\n        version: str = \"alpha\"\n\n        def __repr__(self):\n            return f\"Project: {self.name}\\nVersion: {self.version}\"\n\n\n    if __name__ == \"__main__\":\n        print(f\"Project configuration:\\n{ProjectConfiguration}\")\n\n        try:\n            ProjectConfiguration.name = \"NewProjectName\"\n        except cc.ConstError as err:\n            print(f\"Error: {err}\")\n\n        try:\n            ProjectConfiguration.version = \"beta\"\n        except cc.ConstError as err:\n            print(f\"Error: {err}\")\n    ```\n\n    This program will produce the following output:\n    ```\n    john = John Doe\n    Error: Cannot modify const attribute `first_name` of class `Person`\n    Error: Cannot modify const attribute `last_name` of class `Person`\n    ```\n\n<br />\n<br />\n\n## Examples\n\nThe project examples shown in the [Tutorial](#tutorial) section can be found in the `examples` directory.\n\nTo run the example programs you need to install the PyConstClasses package into your python environment. You can install it via `pip` of using a local distribution build (the process is described in the [Dev notes](#dev-notes) section).\n\n<br />\n<br />\n\n## Dev notes\n\n### Environment setup:\n\nTo be able to build or test the project create a python virtual environment\n\n```shell\npython -m venv cc_venv\nsource cc_venv/bin/activate\npip install -r requirements-dev.txt\n```\n\n> [!NOTE]\n> If any package listed in `requirements-dev.txt` is no longer required or if there is a new required package, update the requirements file using: `pip freeze > requirements-dev.txt`\n\n### Building\n\nTo build the package, run:\n```shell\npython -m build\n```\n\nThis will generate the `dist` directory with the `.whl` file. To locally test if the distribution is correct, you can run:\n```shell\npip install dist/pyconstclasses-<version>-py3-none-any.whl --force-reinstall\n```\n\n> [!NOTE]\n> To test the package build locally it is recommended to use a clean virtual environment.\n\n### Testing:\n\nThe project uses `pytest` and `tox` for testing purposes.\n* To run the tests for the current python interpreter run: `pytest -v`\n* To run tests for all supported python versions run: `tox`\n\n### Coverage\n\nTo generate a test coverage report you can run `tox` which will automatically generate `json` and `xml` reports (the types of coverage reports can be adjusted in `tox.ini`).\n\nYou can also generate the coverage reports manually with `pytest`, e.g.:\n```shell\npytest -v --cov=constclasses --cov-report=xml --cov-report=html\n```\n\n> [!NOTE]\n> When testing the project or generating coverate reports, python (or it's packages) will generate additional files (cache file, etc.). To easily clean those files from the working directory run `./scripts/cleanup.sh`\n\n### Formatting:\n\nThe project uses `black` and `isort` for formatting purposes. To format the source code use the prepared script:\n```shell\n./scripts/format.sh\n```\nYou can also use the `black` and `isort` packages directly, e.g.\n```shell\npython -m <black/isort> <path> (--check)\n```\n\n<br />\n<br />\n\n## Licence\n\nThe `PyConstClasses` project uses the [MIT Licence](https://opensource.org/license/mit/)\n",
    "bugtrack_url": null,
    "license": "MIT License  Copyright (c) 2024 Jakub Musia\u0142  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ",
    "summary": "Package with const class decoratos and utility",
    "version": "1.0.5",
    "project_urls": {
        "Repository": "https://github.com/SpectraL519/pyconstclasses.git"
    },
    "split_keywords": [
        "const",
        " const class",
        " const classes"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "4f7fdf5188dc84108f443e91d4c47f037fc55adc78adedc9c392bec5329cba96",
                "md5": "a79ff1744c69ca995dac9405f97c364b",
                "sha256": "97b94403eded4643c066b90d8d0ff88fe19915617d5eef88762fa1b05d6f400c"
            },
            "downloads": -1,
            "filename": "pyconstclasses-1.0.5-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "a79ff1744c69ca995dac9405f97c364b",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.9",
            "size": 10108,
            "upload_time": "2024-09-04T11:39:11",
            "upload_time_iso_8601": "2024-09-04T11:39:11.288371Z",
            "url": "https://files.pythonhosted.org/packages/4f/7f/df5188dc84108f443e91d4c47f037fc55adc78adedc9c392bec5329cba96/pyconstclasses-1.0.5-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "f7ca2da1277ee562b28890e9bf838740bd388ca841704129015ce5493e3aeef0",
                "md5": "cab2ae7e84ec6df4dc9a8666f06620e1",
                "sha256": "42ee931fca321e1dcb4d9799f96d68801f745f536d5030630928f16ce3b3dfcc"
            },
            "downloads": -1,
            "filename": "pyconstclasses-1.0.5.tar.gz",
            "has_sig": false,
            "md5_digest": "cab2ae7e84ec6df4dc9a8666f06620e1",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.9",
            "size": 15429,
            "upload_time": "2024-09-04T11:39:12",
            "upload_time_iso_8601": "2024-09-04T11:39:12.437542Z",
            "url": "https://files.pythonhosted.org/packages/f7/ca/2da1277ee562b28890e9bf838740bd388ca841704129015ce5493e3aeef0/pyconstclasses-1.0.5.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-09-04 11:39:12",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "SpectraL519",
    "github_project": "pyconstclasses",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "tox": true,
    "lcname": "pyconstclasses"
}
        
Elapsed time: 0.30781s