instancemethod


Nameinstancemethod JSON
Version 2.0 PyPI version JSON
download
home_pagehttps://github.com/Braden2n/InstanceMethod
SummaryRestrict method calls to instances of the owner class.
upload_time2024-03-23 14:26:47
maintainerNone
docs_urlNone
authorBraden Toone
requires_python>=3.9
licenseMIT License Copyright (c) 2024 Braden Douglas Toone 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 instance method restrict class call
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # instancemethod

Sections:

- [Purpose](#purpose)
- [Contents](#contents)
- [Installation](#installation)
- [Usage](#usage)
    - [Declaration](#declaration)
    - [Valid Usage](#valid-usage)
    - [Invalid Usage](#invalid-usage)
- [Issues/Limitations](#issueslimitations)
- [Testing](#testing)
- [Performance](#performance)
    - [Current Stats](#current-stats)
    - [Bottlenecks](#bottlenecks)

## Purpose

This package containing code and its example usage for restricting
method calls to instances of the class or subclass that contains the
method. Support has been added for nesting classes as attributes.

## Contents

This package contains one module written in pure Python (3.5 or newer)
with the following code blocks:

- `instancemethod`: Higher order function for wrapping methods
- `NotAnInstanceError`: Error raised when validation fails

## Installation

This package is distributed to PyPi, and can be installed with either
of the following commands:

- `pip install instancemethod`
- `pip3 install instancemethod`

## Usage

Use the Python decorator (`@`) symbol along with the `instancemethod`
function to wrap a method and designate it as an instance method.

### Declaration

    class Foo:
        def __init__():
            ...
    
        @instancemethod
        def bar():
            ...

### Valid Usage

    foo = Foo()
    bar = foo.bar()

### Invalid Usage

    bar = Foo.bar()

Returns

    NotAnInstanceError:
    ...

## Issues/Limitations

There are currently no known stability or performance issues, so this
package has been marked as:

***Production***

Previous [bottlenecks](#bottlenecks), a
[deep-dive](#bottleneck-deep-dive) into their causes, and the
explanation of their [solution](#bottleneck-solution) are located in
the [Bottlenecks](#bottlenecks) portion of the
[Performance](#performance) section.

## Testing

The following test cases are currently implemented:

- Decorator allows the following valid cases:
    - Calling method from an instance of a class
        - Foo().bar()
    - Calling method from an instance of a subclass
        - SubFoo().bar()
    - Calling method from an instance of a class in a nested hierarchy
        - Foo.Bar().foo()
- Decorator blocks all other cases:
    - Calling method without an instance of any above-mentioned cases
        - Fuzzing implemented using instances of all built-in types
          and non-inheriting classes

## Performance

Performance testing is implemented for all valid test cases against a
control method. The control method is
decorated with a `null_decorator` decorator that adds no functionality.
This is compared to the `instancemethod` decorator; 1 Million
function calls are made for each.

### Current Stats

The `instancemethod` decorator is currently:
1.65
times slower than `null_decorator` over the course of 1 Million calls.

Average Nanoseconds per Call:

- `instancemethod`: 140
- `null_decorator`: 85

***No*** appreciable difference has been found between the valid test
cases.

### Bottlenecks

Previous versions contained three main bottlenecks that hindered
performance significantly (50x slower than `null_decorator`):

- The usage of the `inspect`.`getmodule` function
- The usage of the `inspect`.`getmembers` function
- The ownership attribute loop

### Bottleneck Deep-Dive

The `inspect` module and its `getmodule` and `getmembers` functions
are necessary for determining the class that has direct ownership of
the wrapped method. In previous versions, both the `getmodule` and
`getmembers` functions were used in the wrapper function declared
inside the higher order decorator.

Although marginal (5%) performance benefits were found by hoisting the
`getmodule` up to the scope of the decorator function, by shifting the
computation burden to declaration time as opposed to call time, the
`getmembers` function was unable to be hoisted due to the changing
state of a module at load time versus call time. Some performance was
reclaimed by the use of a lambda filtering predicate, but much was
left to be desired.

Along with the `inspect` module functions, the "ownership attribute"
loop was another potential bottleneck. Since the only obvious way to
ascertain the class was through the method's fully qualified name,
accessing nested classes to reach down towards the method's direct
owner needed to be done using string attribute searches. Although the
loop is not too computationally intensive, this could be a bottleneck
for deeply nested or inherited class structures.

### Bottleneck Solution

The current solution in place was to extract the declaration and
computation of these bottlenecks to a separate function in the
package's local scope, as opposed to the decorator's scope, and
enabling LRU caching from the `functools` module.

For those unfamiliar, the lru_cache function, when used as a
decorator, creates a memory-optimized call-result caching solution
that exchanges the full computation requirements of a function call
for a dictionary lookup of the result.

Since the penalty for a first-time call is
~4 Microseconds, the caching of the results on a per-method basis
provides a performance increase of 3,000%. This is because the
dictionary lookup has a time complexity of, on average, O(1) that
results in ~125 Nanosecond follow-up calls.

## Author

Braden Toone is the sole author and maintainer of this code, and can
be contacted via email at braden@toonetown.com

## License

This package is licensed under the OSI Approved MIT License for free
commercial and personal use as stated in the LICENSE file.

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/Braden2n/InstanceMethod",
    "name": "instancemethod",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.9",
    "maintainer_email": "Braden Toone <braden@toonetown.com>",
    "keywords": "instance, method, restrict, class, call",
    "author": "Braden Toone",
    "author_email": "Braden Toone <braden@toonetown.com>",
    "download_url": "https://files.pythonhosted.org/packages/ce/06/0c238d6cad016abc8eb0683b5e3e913882ff832adc4773be42c2cf0d621a/instancemethod-2.0.tar.gz",
    "platform": null,
    "description": "# instancemethod\n\nSections:\n\n- [Purpose](#purpose)\n- [Contents](#contents)\n- [Installation](#installation)\n- [Usage](#usage)\n    - [Declaration](#declaration)\n    - [Valid Usage](#valid-usage)\n    - [Invalid Usage](#invalid-usage)\n- [Issues/Limitations](#issueslimitations)\n- [Testing](#testing)\n- [Performance](#performance)\n    - [Current Stats](#current-stats)\n    - [Bottlenecks](#bottlenecks)\n\n## Purpose\n\nThis package containing code and its example usage for restricting\nmethod calls to instances of the class or subclass that contains the\nmethod. Support has been added for nesting classes as attributes.\n\n## Contents\n\nThis package contains one module written in pure Python (3.5 or newer)\nwith the following code blocks:\n\n- `instancemethod`: Higher order function for wrapping methods\n- `NotAnInstanceError`: Error raised when validation fails\n\n## Installation\n\nThis package is distributed to PyPi, and can be installed with either\nof the following commands:\n\n- `pip install instancemethod`\n- `pip3 install instancemethod`\n\n## Usage\n\nUse the Python decorator (`@`) symbol along with the `instancemethod`\nfunction to wrap a method and designate it as an instance method.\n\n### Declaration\n\n    class Foo:\n        def __init__():\n            ...\n    \n        @instancemethod\n        def bar():\n            ...\n\n### Valid Usage\n\n    foo = Foo()\n    bar = foo.bar()\n\n### Invalid Usage\n\n    bar = Foo.bar()\n\nReturns\n\n    NotAnInstanceError:\n    ...\n\n## Issues/Limitations\n\nThere are currently no known stability or performance issues, so this\npackage has been marked as:\n\n***Production***\n\nPrevious [bottlenecks](#bottlenecks), a\n[deep-dive](#bottleneck-deep-dive) into their causes, and the\nexplanation of their [solution](#bottleneck-solution) are located in\nthe [Bottlenecks](#bottlenecks) portion of the\n[Performance](#performance) section.\n\n## Testing\n\nThe following test cases are currently implemented:\n\n- Decorator allows the following valid cases:\n    - Calling method from an instance of a class\n        - Foo().bar()\n    - Calling method from an instance of a subclass\n        - SubFoo().bar()\n    - Calling method from an instance of a class in a nested hierarchy\n        - Foo.Bar().foo()\n- Decorator blocks all other cases:\n    - Calling method without an instance of any above-mentioned cases\n        - Fuzzing implemented using instances of all built-in types\n          and non-inheriting classes\n\n## Performance\n\nPerformance testing is implemented for all valid test cases against a\ncontrol method. The control method is\ndecorated with a `null_decorator` decorator that adds no functionality.\nThis is compared to the `instancemethod` decorator; 1 Million\nfunction calls are made for each.\n\n### Current Stats\n\nThe `instancemethod` decorator is currently:\n1.65\ntimes slower than `null_decorator` over the course of 1 Million calls.\n\nAverage Nanoseconds per Call:\n\n- `instancemethod`: 140\n- `null_decorator`: 85\n\n***No*** appreciable difference has been found between the valid test\ncases.\n\n### Bottlenecks\n\nPrevious versions contained three main bottlenecks that hindered\nperformance significantly (50x slower than `null_decorator`):\n\n- The usage of the `inspect`.`getmodule` function\n- The usage of the `inspect`.`getmembers` function\n- The ownership attribute loop\n\n### Bottleneck Deep-Dive\n\nThe `inspect` module and its `getmodule` and `getmembers` functions\nare necessary for determining the class that has direct ownership of\nthe wrapped method. In previous versions, both the `getmodule` and\n`getmembers` functions were used in the wrapper function declared\ninside the higher order decorator.\n\nAlthough marginal (5%) performance benefits were found by hoisting the\n`getmodule` up to the scope of the decorator function, by shifting the\ncomputation burden to declaration time as opposed to call time, the\n`getmembers` function was unable to be hoisted due to the changing\nstate of a module at load time versus call time. Some performance was\nreclaimed by the use of a lambda filtering predicate, but much was\nleft to be desired.\n\nAlong with the `inspect` module functions, the \"ownership attribute\"\nloop was another potential bottleneck. Since the only obvious way to\nascertain the class was through the method's fully qualified name,\naccessing nested classes to reach down towards the method's direct\nowner needed to be done using string attribute searches. Although the\nloop is not too computationally intensive, this could be a bottleneck\nfor deeply nested or inherited class structures.\n\n### Bottleneck Solution\n\nThe current solution in place was to extract the declaration and\ncomputation of these bottlenecks to a separate function in the\npackage's local scope, as opposed to the decorator's scope, and\nenabling LRU caching from the `functools` module.\n\nFor those unfamiliar, the lru_cache function, when used as a\ndecorator, creates a memory-optimized call-result caching solution\nthat exchanges the full computation requirements of a function call\nfor a dictionary lookup of the result.\n\nSince the penalty for a first-time call is\n~4 Microseconds, the caching of the results on a per-method basis\nprovides a performance increase of 3,000%. This is because the\ndictionary lookup has a time complexity of, on average, O(1) that\nresults in ~125 Nanosecond follow-up calls.\n\n## Author\n\nBraden Toone is the sole author and maintainer of this code, and can\nbe contacted via email at braden@toonetown.com\n\n## License\n\nThis package is licensed under the OSI Approved MIT License for free\ncommercial and personal use as stated in the LICENSE file.\n",
    "bugtrack_url": null,
    "license": "MIT License  Copyright (c) 2024 Braden Douglas Toone  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": "Restrict method calls to instances of the owner class.",
    "version": "2.0",
    "project_urls": {
        "Changelog": "https://github.com/Braden2n/InstanceMethod/activity",
        "Documentation": "https://github.com/Braden2n/InstanceMethod",
        "Homepage": "https://github.com/Braden2n/InstanceMethod",
        "Issues": "https://github.com/Braden2n/InstanceMethod/issues",
        "Repository": "https://github.com"
    },
    "split_keywords": [
        "instance",
        " method",
        " restrict",
        " class",
        " call"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "968396ec91b5219c26d12e33efb63f9fb40bf7329b9ced5ad447c212a546c673",
                "md5": "276b61a0b3aabc2ea394efce3eb3e7bd",
                "sha256": "11c6d3003495b2b8bfeea8a7566fde32d62b0cb0af47aa11ba3bfc7c256c5c02"
            },
            "downloads": -1,
            "filename": "instancemethod-2.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "276b61a0b3aabc2ea394efce3eb3e7bd",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.9",
            "size": 5037,
            "upload_time": "2024-03-23T14:26:45",
            "upload_time_iso_8601": "2024-03-23T14:26:45.832264Z",
            "url": "https://files.pythonhosted.org/packages/96/83/96ec91b5219c26d12e33efb63f9fb40bf7329b9ced5ad447c212a546c673/instancemethod-2.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "ce060c238d6cad016abc8eb0683b5e3e913882ff832adc4773be42c2cf0d621a",
                "md5": "5b2ebe31621b3277ca5711712883aa81",
                "sha256": "492c1839ad8f61d3f695f14c9f8bcfccf6fad1d73ec6863781e94114464c7fb9"
            },
            "downloads": -1,
            "filename": "instancemethod-2.0.tar.gz",
            "has_sig": false,
            "md5_digest": "5b2ebe31621b3277ca5711712883aa81",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.9",
            "size": 6167,
            "upload_time": "2024-03-23T14:26:47",
            "upload_time_iso_8601": "2024-03-23T14:26:47.012007Z",
            "url": "https://files.pythonhosted.org/packages/ce/06/0c238d6cad016abc8eb0683b5e3e913882ff832adc4773be42c2cf0d621a/instancemethod-2.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-03-23 14:26:47",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "Braden2n",
    "github_project": "InstanceMethod",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "instancemethod"
}
        
Elapsed time: 0.20805s