pymagic9


Namepymagic9 JSON
Version 0.9.0 PyPI version JSON
download
home_pagehttps://github.com/sammnnz/pymagic9
SummaryThis is a Python library based on calling of frame's stack at runtime and mainly implements some C# features.
upload_time2023-10-22 01:48:12
maintainer
docs_urlNone
authorSam Nazarov
requires_python!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,<3.11,>=2.7
licenseApache License 2.0
keywords c# frame getframe isfunctionincallchain nameof stackframe
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage
            # pymagic9

[![license](https://img.shields.io/badge/License-APACHE_2.0-yellow.svg)](http://www.apache.org/licenses/)
<a><img src="https://img.shields.io/badge/python-2.7 | 3.6 | 3.7 | 3.8 | 3.9 | 3.10 -blue.svg"></a>
![Tests](https://github.com/sammnnz/pymagic9/actions/workflows/tests.yml/badge.svg)
[![codecov](https://codecov.io/gh/sammnnz/pymagic9/branch/master/graph/badge.svg?token=qQAiKKnctA)](https://codecov.io/gh/sammnnz/pymagic9)

This is a Python library based on calling the stack of frames at runtime and analyzing the code object of frames. Basically, it implements some C# features. For example, it contains the `nameof` function and `auto-implemented properties`. See the [documentation](https://sammnnz.github.io/pymagic9/) for more information.

## Installation

You can install `pymagic9` using pip:
~~~~shell
pip install pymagic9
~~~~

## Features

**[getframe](https://sammnnz.github.io/pymagic9/latest/api-docs/pymagic9.html#pymagic9.pymagic9.getframe)**: The [sys._getframe](https://docs.python.org/3/library/sys.html?highlight=_getframe#sys._getframe) function is used here if it exists in the version of python being used. Otherwise, the [_getframe](https://sammnnz.github.io/pymagic9/latest/api-docs/pymagic9.html#pymagic9.pymagic9._getframe) polyfill is used.

**[isemptyfunction](https://sammnnz.github.io/pymagic9/latest/api-docs/pymagic9.html#pymagic9.pymagic9.isemptyfunction)**: Checks if a function is empty or not.

**[isfunctionincallchain](https://sammnnz.github.io/pymagic9/latest/api-docs/pymagic9.html#pymagic9.pymagic9.isfunctionincallchain)**: Determines whether the given function object or code object is present in the call chain.

**[nameof](https://sammnnz.github.io/pymagic9/latest/api-docs/pymagic9.html#pymagic9.pymagic9.nameof)**: This function correctly determines the "name" of an object, without being tied to the object itself. It can be used to retrieve the name of variables, functions, classes, modules, and more.

**[PropertyMeta](https://sammnnz.github.io/pymagic9/latest/api-docs/pymagic9.html#pymagic9.pymagic9.PropertyMeta)**: This metaclass allows you to create `auto-implemented properties` (like in C#, where you can declare properties without explicitly defining a getter and setter), for which you can use an ellipsis or empty functions to indicate that the Python itself would create the auto-implemented accessor.

## Usage of `auto-implemented properties`

1. Import the PropertyMeta metaclass and assign it as a metaclass for the desired class:
~~~~python
from pymagic9 import PropertyMeta


class Person(metaclass=PropertyMeta):
    pass
~~~~
2. Create properties in this class with empty accessors (using empty function or ellipsis) to indicate that this property will be auto-implemented:
~~~~python
from pymagic9 import PropertyMeta


class Person(metaclass=PropertyMeta):
    """class Person"""
    def __init__(self, name):
        self.name = name

    name = property(fget=...,)           # readonly property
    age = property(fget=..., fset=...,)  # ordinary property
~~~~
3. Now for an `ordinary` property we can get and put values into it at any time. But for a `readonly` property, you can put a value into it only once, at the time of creating an instance of the class:
~~~~python
from pymagic9 import PropertyMeta


class Person(metaclass=PropertyMeta):
    """class Person"""
    def __init__(self, name):
        self.name = name
        # self.name = "Sam"  # raise AttributeError: 'property' is readonly (reassigning value)

    name = property(fget=...,)           # readonly property
    age = property(fget=..., fset=...,)  # ordinary property

    
if __name__ == "__main__":
    person = Person("Tom")
    person.age = 24
    print(person.name + ',', person.age)  # Tom, 24
    # person.name = "Sam"  # raise AttributeError: 'property' is readonly
~~~~
4. To delete a property value, use the `del` operator:
~~~~python
from pymagic9 import PropertyMeta


class Person(metaclass=PropertyMeta):
    """class Person"""
    def __init__(self, name):
        self.name = name

    name = property(fget=...,)           # readonly property
    age = property(fget=..., fset=...,)  # ordinary property

    
if __name__ == "__main__":
    person = Person("Tom")
    person.age = 24
    print(person.name + ',', person.age)  # Tom, 24
    del person.name
    # print(person.name)  # raise AttributeError: auto-implemented field does not exist or has already been erased
~~~~
5. If the `getter` is specified by an empty accessor (using empty function or ellipsis), and the `setter` is not an empty function, then `setter` will also be called. This can be used as a callback when assigning a value to a property:
~~~~python
from pymagic9 import nameof, PropertyMeta


def NotifyPropertyChanged(propertyname, value):
    """Notify property changed"""
    # Do something
    print(propertyname + ',', value)


class Person(metaclass=PropertyMeta):
    """class Person"""
    def __init__(self, name):
        self.name = name

    name = property(fget=...,)           # readonly property
    age = property(fget=..., fset=...,)  # ordinary property
    
    @property
    def height(self):
        """Person height in cm"""
        return
    
    @height.setter
    def height(self, value):
        NotifyPropertyChanged(nameof(self.height), value)


if __name__ == "__main__":
    person = Person("Tom")
    person.age = 24
    print(person.name + ',', person.age)  # Tom, 24
    person.height = 180  # height, 180
~~~~
6. Similar code for `Python 2.7` looks like this:
~~~~python
from pymagic9 import nameof, PropertyMeta

__metaclass__ = PropertyMeta


def NotifyPropertyChanged(propertyname, value):
    """Notify property changed"""
    # Do something
    print(propertyname + ', ' + str(value))
    
    
class Person:
    """class Person"""
    def __init__(self, name):
        self.name = name

    name = property(fget=Ellipsis,)                # readonly property
    age = property(fget=Ellipsis, fset=Ellipsis,)  # ordinary property
    
    @property
    def height(self):
        """Person height in cm"""
        return
    
    @height.setter
    def height(self, value):
        NotifyPropertyChanged(nameof(self.height), value)


if __name__ == "__main__":
    person = Person("Tom")
    person.age = 24
    print(person.name + ', ' + str(person.age))  # Tom, 24
    person.height = 180  # height, 180
~~~~
The detailed operating principle is described in the [documentation](https://sammnnz.github.io/pymagic9/latest/api-docs/pymagic9.html#pymagic9.pymagic9.PropertyMeta).

## Compatibility

`pymagic9` is compatible with the following versions of Python:

- CPython 2.7
- CPython 3.6
- CPython 3.7
- CPython 3.8
- CPython 3.9
- CPython 3.10

It is supported on Windows, Ubuntu, and MacOS platforms.

## Documentation

For more information and detailed usage examples, please refer to the [documentation](https://sammnnz.github.io/pymagic9/).

## License

This project is licensed under the Apache License 2.0. See the [LICENSE](https://github.com/sammnnz/pymagic9/blob/master/LICENSE) file for more details.

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/sammnnz/pymagic9",
    "name": "pymagic9",
    "maintainer": "",
    "docs_url": null,
    "requires_python": "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,<3.11,>=2.7",
    "maintainer_email": "",
    "keywords": "C#,frame,getframe,isfunctionincallchain,nameof,stackframe",
    "author": "Sam Nazarov",
    "author_email": "samnnazarov@gmail.com",
    "download_url": "https://files.pythonhosted.org/packages/9b/19/614a7a412bd438063f39206640b7471455b53f2f8c1a4aff88a40ad34216/pymagic9-0.9.0.tar.gz",
    "platform": "any",
    "description": "# pymagic9\r\n\r\n[![license](https://img.shields.io/badge/License-APACHE_2.0-yellow.svg)](http://www.apache.org/licenses/)\r\n<a><img src=\"https://img.shields.io/badge/python-2.7 | 3.6 | 3.7 | 3.8 | 3.9 | 3.10 -blue.svg\"></a>\r\n![Tests](https://github.com/sammnnz/pymagic9/actions/workflows/tests.yml/badge.svg)\r\n[![codecov](https://codecov.io/gh/sammnnz/pymagic9/branch/master/graph/badge.svg?token=qQAiKKnctA)](https://codecov.io/gh/sammnnz/pymagic9)\r\n\r\nThis is a Python library based on calling the stack of frames at runtime and analyzing the code object of frames. Basically, it implements some C# features. For example, it contains the `nameof` function and `auto-implemented properties`. See the [documentation](https://sammnnz.github.io/pymagic9/) for more information.\r\n\r\n## Installation\r\n\r\nYou can install `pymagic9` using pip:\r\n~~~~shell\r\npip install pymagic9\r\n~~~~\r\n\r\n## Features\r\n\r\n**[getframe](https://sammnnz.github.io/pymagic9/latest/api-docs/pymagic9.html#pymagic9.pymagic9.getframe)**: The [sys._getframe](https://docs.python.org/3/library/sys.html?highlight=_getframe#sys._getframe) function is used here if it exists in the version of python being used. Otherwise, the [_getframe](https://sammnnz.github.io/pymagic9/latest/api-docs/pymagic9.html#pymagic9.pymagic9._getframe) polyfill is used.\r\n\r\n**[isemptyfunction](https://sammnnz.github.io/pymagic9/latest/api-docs/pymagic9.html#pymagic9.pymagic9.isemptyfunction)**: Checks if a function is empty or not.\r\n\r\n**[isfunctionincallchain](https://sammnnz.github.io/pymagic9/latest/api-docs/pymagic9.html#pymagic9.pymagic9.isfunctionincallchain)**: Determines whether the given function object or code object is present in the call chain.\r\n\r\n**[nameof](https://sammnnz.github.io/pymagic9/latest/api-docs/pymagic9.html#pymagic9.pymagic9.nameof)**: This function correctly determines the \"name\" of an object, without being tied to the object itself. It can be used to retrieve the name of variables, functions, classes, modules, and more.\r\n\r\n**[PropertyMeta](https://sammnnz.github.io/pymagic9/latest/api-docs/pymagic9.html#pymagic9.pymagic9.PropertyMeta)**: This metaclass allows you to create `auto-implemented properties` (like in C#, where you can declare properties without explicitly defining a getter and setter), for which you can use an ellipsis or empty functions to indicate that the Python itself would create the auto-implemented accessor.\r\n\r\n## Usage of `auto-implemented properties`\r\n\r\n1. Import the PropertyMeta metaclass and assign it as a metaclass for the desired class:\r\n~~~~python\r\nfrom pymagic9 import PropertyMeta\r\n\r\n\r\nclass Person(metaclass=PropertyMeta):\r\n    pass\r\n~~~~\r\n2. Create properties in this class with empty accessors (using empty function or ellipsis) to indicate that this property will be auto-implemented:\r\n~~~~python\r\nfrom pymagic9 import PropertyMeta\r\n\r\n\r\nclass Person(metaclass=PropertyMeta):\r\n    \"\"\"class Person\"\"\"\r\n    def __init__(self, name):\r\n        self.name = name\r\n\r\n    name = property(fget=...,)           # readonly property\r\n    age = property(fget=..., fset=...,)  # ordinary property\r\n~~~~\r\n3. Now for an `ordinary` property we can get and put values into it at any time. But for a `readonly` property, you can put a value into it only once, at the time of creating an instance of the class:\r\n~~~~python\r\nfrom pymagic9 import PropertyMeta\r\n\r\n\r\nclass Person(metaclass=PropertyMeta):\r\n    \"\"\"class Person\"\"\"\r\n    def __init__(self, name):\r\n        self.name = name\r\n        # self.name = \"Sam\"  # raise AttributeError: 'property' is readonly (reassigning value)\r\n\r\n    name = property(fget=...,)           # readonly property\r\n    age = property(fget=..., fset=...,)  # ordinary property\r\n\r\n    \r\nif __name__ == \"__main__\":\r\n    person = Person(\"Tom\")\r\n    person.age = 24\r\n    print(person.name + ',', person.age)  # Tom, 24\r\n    # person.name = \"Sam\"  # raise AttributeError: 'property' is readonly\r\n~~~~\r\n4. To delete a property value, use the `del` operator:\r\n~~~~python\r\nfrom pymagic9 import PropertyMeta\r\n\r\n\r\nclass Person(metaclass=PropertyMeta):\r\n    \"\"\"class Person\"\"\"\r\n    def __init__(self, name):\r\n        self.name = name\r\n\r\n    name = property(fget=...,)           # readonly property\r\n    age = property(fget=..., fset=...,)  # ordinary property\r\n\r\n    \r\nif __name__ == \"__main__\":\r\n    person = Person(\"Tom\")\r\n    person.age = 24\r\n    print(person.name + ',', person.age)  # Tom, 24\r\n    del person.name\r\n    # print(person.name)  # raise AttributeError: auto-implemented field does not exist or has already been erased\r\n~~~~\r\n5. If the `getter` is specified by an empty accessor (using empty function or ellipsis), and the `setter` is not an empty function, then `setter` will also be called. This can be used as a callback when assigning a value to a property:\r\n~~~~python\r\nfrom pymagic9 import nameof, PropertyMeta\r\n\r\n\r\ndef NotifyPropertyChanged(propertyname, value):\r\n    \"\"\"Notify property changed\"\"\"\r\n    # Do something\r\n    print(propertyname + ',', value)\r\n\r\n\r\nclass Person(metaclass=PropertyMeta):\r\n    \"\"\"class Person\"\"\"\r\n    def __init__(self, name):\r\n        self.name = name\r\n\r\n    name = property(fget=...,)           # readonly property\r\n    age = property(fget=..., fset=...,)  # ordinary property\r\n    \r\n    @property\r\n    def height(self):\r\n        \"\"\"Person height in cm\"\"\"\r\n        return\r\n    \r\n    @height.setter\r\n    def height(self, value):\r\n        NotifyPropertyChanged(nameof(self.height), value)\r\n\r\n\r\nif __name__ == \"__main__\":\r\n    person = Person(\"Tom\")\r\n    person.age = 24\r\n    print(person.name + ',', person.age)  # Tom, 24\r\n    person.height = 180  # height, 180\r\n~~~~\r\n6. Similar code for `Python 2.7` looks like this:\r\n~~~~python\r\nfrom pymagic9 import nameof, PropertyMeta\r\n\r\n__metaclass__ = PropertyMeta\r\n\r\n\r\ndef NotifyPropertyChanged(propertyname, value):\r\n    \"\"\"Notify property changed\"\"\"\r\n    # Do something\r\n    print(propertyname + ', ' + str(value))\r\n    \r\n    \r\nclass Person:\r\n    \"\"\"class Person\"\"\"\r\n    def __init__(self, name):\r\n        self.name = name\r\n\r\n    name = property(fget=Ellipsis,)                # readonly property\r\n    age = property(fget=Ellipsis, fset=Ellipsis,)  # ordinary property\r\n    \r\n    @property\r\n    def height(self):\r\n        \"\"\"Person height in cm\"\"\"\r\n        return\r\n    \r\n    @height.setter\r\n    def height(self, value):\r\n        NotifyPropertyChanged(nameof(self.height), value)\r\n\r\n\r\nif __name__ == \"__main__\":\r\n    person = Person(\"Tom\")\r\n    person.age = 24\r\n    print(person.name + ', ' + str(person.age))  # Tom, 24\r\n    person.height = 180  # height, 180\r\n~~~~\r\nThe detailed operating principle is described in the [documentation](https://sammnnz.github.io/pymagic9/latest/api-docs/pymagic9.html#pymagic9.pymagic9.PropertyMeta).\r\n\r\n## Compatibility\r\n\r\n`pymagic9` is compatible with the following versions of Python:\r\n\r\n- CPython 2.7\r\n- CPython 3.6\r\n- CPython 3.7\r\n- CPython 3.8\r\n- CPython 3.9\r\n- CPython 3.10\r\n\r\nIt is supported on Windows, Ubuntu, and MacOS platforms.\r\n\r\n## Documentation\r\n\r\nFor more information and detailed usage examples, please refer to the [documentation](https://sammnnz.github.io/pymagic9/).\r\n\r\n## License\r\n\r\nThis project is licensed under the Apache License 2.0. See the [LICENSE](https://github.com/sammnnz/pymagic9/blob/master/LICENSE) file for more details.\r\n",
    "bugtrack_url": null,
    "license": "Apache License 2.0",
    "summary": "This is a Python library based on calling of frame's stack at runtime and mainly implements some C# features.",
    "version": "0.9.0",
    "project_urls": {
        "Bug Tracker": "https://github.com/sammnnz/pymagic9/issues",
        "Changelog": "https://github.com/sammnnz/pymagic9/blob/master/CHANGELOG.md",
        "Homepage": "https://github.com/sammnnz/pymagic9",
        "Source code": "https://github.com/sammnnz/pymagic9"
    },
    "split_keywords": [
        "c#",
        "frame",
        "getframe",
        "isfunctionincallchain",
        "nameof",
        "stackframe"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "3ce07933525d8f9054165ab250c49465017153c53cfaacf0910507f6344f07bb",
                "md5": "4669e5177d5aa517c51c06850d4ad49a",
                "sha256": "2aba7f4d686a6f114cc3e7efec5719482aefc069faf1efdd9c8084f360644d32"
            },
            "downloads": -1,
            "filename": "pymagic9-0.9.0-py2.py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "4669e5177d5aa517c51c06850d4ad49a",
            "packagetype": "bdist_wheel",
            "python_version": "py2.py3",
            "requires_python": "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,<3.11,>=2.7",
            "size": 15442,
            "upload_time": "2023-10-22T01:48:10",
            "upload_time_iso_8601": "2023-10-22T01:48:10.041362Z",
            "url": "https://files.pythonhosted.org/packages/3c/e0/7933525d8f9054165ab250c49465017153c53cfaacf0910507f6344f07bb/pymagic9-0.9.0-py2.py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "9b19614a7a412bd438063f39206640b7471455b53f2f8c1a4aff88a40ad34216",
                "md5": "8976a8bc011adc3995a53993e0541068",
                "sha256": "d6e382c2f4083458d134636f911fbd9bc980f537f5caedf24dadc237e3696b48"
            },
            "downloads": -1,
            "filename": "pymagic9-0.9.0.tar.gz",
            "has_sig": false,
            "md5_digest": "8976a8bc011adc3995a53993e0541068",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,<3.11,>=2.7",
            "size": 17272,
            "upload_time": "2023-10-22T01:48:12",
            "upload_time_iso_8601": "2023-10-22T01:48:12.179844Z",
            "url": "https://files.pythonhosted.org/packages/9b/19/614a7a412bd438063f39206640b7471455b53f2f8c1a4aff88a40ad34216/pymagic9-0.9.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-10-22 01:48:12",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "sammnnz",
    "github_project": "pymagic9",
    "travis_ci": false,
    "coveralls": true,
    "github_actions": true,
    "requirements": [],
    "tox": true,
    "lcname": "pymagic9"
}
        
Elapsed time: 0.23783s