oop-ext


Nameoop-ext JSON
Version 2.2.0 PyPI version JSON
download
home_pagehttp://github.com/ESSS/oop-ext
SummaryOOP Extensions is a set of utilities for object oriented programming not found on Python's standard library.
upload_time2024-10-24 12:20:39
maintainerNone
docs_urlNone
authorESSS
requires_python>=3.10
licenseMIT license
keywords oop_ext
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            ======================================================================
OOP Extensions
======================================================================

.. image:: https://img.shields.io/pypi/v/oop-ext.svg
    :target: https://pypi.python.org/pypi/oop-ext

.. image:: https://img.shields.io/pypi/pyversions/oop-ext.svg
    :target: https://pypi.org/project/oop-ext

.. image:: https://github.com/ESSS/oop-ext/workflows/build/badge.svg
    :target: https://github.com/ESSS/oop-ext/actions

.. image:: https://codecov.io/gh/ESSS/oop-ext/branch/master/graph/badge.svg
    :target: https://codecov.io/gh/ESSS/oop-ext

.. image:: https://img.shields.io/readthedocs/oop-extensions.svg
    :target: https://oop-extensions.readthedocs.io/en/latest/

.. image:: https://results.pre-commit.ci/badge/github/ESSS/oop-ext/master.svg
    :target: https://results.pre-commit.ci/latest/github/ESSS/oop-ext/master

.. image:: https://sonarcloud.io/api/project_badges/measure?project=ESSS_oop-ext&metric=alert_status
    :target: https://sonarcloud.io/project/overview?id=ESSS_oop-ext


What is OOP Extensions ?
================================================================================

OOP Extensions is a set of utilities for object oriented programming which is missing on Python core libraries.

Usage
================================================================================
``oop_ext`` brings a set of object oriented utilities, it supports the concept of interfaces,
abstract/overridable methods and more. ``oop_ext`` carefully checks that implementations
have the same method signatures as the interface it implements and raises exceptions otherwise.

Here's a simple example showing some nice features:

.. code-block:: python

    from oop_ext.interface import Interface, ImplementsInterface


    class IDisposable(Interface):
        def dispose(self):
            """
            Clears this object
            """

        def is_disposed(self) -> bool:
            """
            Returns True if the object has been cleared
            """


    @ImplementsInterface(IDisposable)
    class MyObject(Disposable):
        def __init__(self):
            super().__init__()
            self._data = [0] * 100
            self._is_disposed = False

        def is_disposed(self) -> bool:
            return self._is_disposed

        def dispose(self):
            self._is_disposed = True
            self._data = []


If any of the two methods in ``MyObject`` are not implemented or have differ signatures than
the ones declared in ``IDisposable``, the ``ImplementsInterface`` decorator will raise an
error during import.

Arbitrary objects can be verified if they implement a certain interface by using ``IsImplementation``:

.. code-block:: python

    from oop_ext.interface import IsImplementation

    my_object = MyObject()
    if IsImplementation(my_object, IDisposable):
        # my_object is guaranteed to implement IDisposable completely
        my_object.dispose()

Alternatively you can assert that an object implements the desired interface with ``AssertImplements``:

.. code-block:: python

    from oop_ext.interface import AssertImplements

    my_object = MyObject()
    AssertImplements(my_object, IDisposable)
    my_object.dispose()


Type Checking
-------------

As of ``1.1.0``, ``oop-ext`` includes inline type annotations and exposes them to user programs.

If you are running a type checker such as mypy on your tests, you may start noticing type errors indicating incorrect usage.
If you run into an error that you believe to be incorrect, please let us know in an issue.

The types were developed against ``mypy`` version 0.800.

See `the docs <https://oop-extensions.readthedocs.io/en/latest/interfaces.html#static-type-checking>`__
for more information.

Contributing
------------

For guidance on setting up a development environment and how to make a
contribution to oop_ext, see the `contributing guidelines`_.

.. _contributing guidelines: https://github.com/ESSS/oop-ext/blob/master/CONTRIBUTING.rst


Release
-------
A reminder for the maintainers on how to make a new release.

Note that the VERSION should follow the semantic versioning as ``X.Y.Z`` (e.g. ``v1.0.5``).

1. Create a ``release-VERSION`` branch from ``upstream/master``.
2. Update ``CHANGELOG.rst``.
3. Push a branch with the changes.
4. Once all builds pass, push a ``VERSION`` tag to ``upstream``.
5. Merge the PR.


2.2.0
-----

**Release**: 2024-10-24

* ``PriorityCallback`` now has type checking support, similar to ``Callback``, with type checked variants: ``PriorityCallback0``, ``PriorityCallback1``, etc (`#128`_).
* ``UnregisterContext`` is now public, meant to be used in type annotations.
* Python 3.10+ is now required.

.. _#128: https://github.com/ESSS/oop-ext/pull/128

2.1.0 (2021-03-19)
------------------

* #48: New type-checker friendly ``proxy = GetProxy(I, obj)`` function as an alternative to ``proxy = I(obj)``. The
  latter is not accepted by type checkers in general because interfaces are protocols, which can't be instantiated.

  Also fixed a type-checking error with ``AsssertImplements``::

      Only concrete class can be given where "Type[Interface]" is expected

  This happens due to `python/mypy#5374 <https://github.com/python/mypy/issues/5374>`__.


2.0.0 (2021-03-10)
------------------

* #47: Interfaces no longer check type annotations at all.

  It was supported initially, but in practice
  this feature has shown up to be an impediment to adopting type annotations incrementally, as it
  discourages adding type annotations to improve existing interfaces, or annotating
  existing implementations without having to update the interface (and all other implementations
  by consequence).

  It was decided to let the static type checker correctly deal with matching type annotations, as
  it can do so more accurately than ``oop-ext`` did before.

1.2.0 (2021-03-09)
------------------

* #43: Fix support for type annotated ``Attribute`` and ``ReadOnlyAttribute``:

  .. code-block:: python

      class IFoo(Interface):
          value: int = Attribute(int)

1.1.2 (2021-02-23)
------------------

* #41: Fix regression introduced in ``1.1.0`` where installing a callback using
  ``callback.After`` or ``callback.Before`` would make a method no longer compliant with
  the signature required by its interface.

1.1.1 (2021-02-23)
------------------

* #38: Reintroduce ``extra_args`` argument to ``Callback._GetKey``, so subclasses can make use
  of it.

* #36: Fix regression introduced in ``1.1.0`` where ``Abstract`` and ``Implements`` decorators
  could no longer be used in interfaces implementations.

1.1.0 (2021-02-19)
------------------

* #25: ``oop-ext`` now includes inline type annotations and exposes them to user programs.

  If you are running a type checker such as mypy on your tests, you may start noticing type errors indicating incorrect usage.
  If you run into an error that you believe to be incorrect, please let us know in an issue.

  The types were developed against ``mypy`` version 0.800.

* #26: New type-checked ``Callback`` variants, ``Callback0``, ``Callback1``, ``Callback2``, etc, providing
  type checking for all operations(calling, ``Register``, etc) at nearly zero runtime cost.

  Example:

  .. code-block:: python

      from oop_ext.foundation.callback import Callback2


      def changed(x: int, v: float) -> None: ...


      on_changed = Callback2[int, float]()
      on_changed(10, 5.25)


* Fixed ``Callbacks.Before`` and ``Callbacks.After`` signatures: previously their signature conveyed
  that they supported multiple callbacks, but it was a mistake which would break callers because
  every parameter after the 2nd would be considered the ``sender_as_parameter`` parameter, which
  was forwarded to ``After`` and ``Before`` functions of the ``_shortcuts.py``
  module.

1.0.0 (2020-10-01)
------------------

* ``Callbacks`` can be used as context manager, which provides a ``Register(callback, function)``,
  which automatically unregisters all functions when the context manager ends.

* ``Callback.Register(function)`` now returns an object with a ``Unregister()`` method, which
  can be used to undo the register call.

0.6.0 (2020-01-31)
==================

* Change back the default value of ``requires_declaration`` to ``True`` and fix an error (#22) where the cache wasn't properly cleared.

0.5.1 (2019-12-20)
------------------

* Fixes an issue (#20) where mocked `classmethods` weren't considered a valid method during internal checks.

0.5.0 (2019-12-12)
------------------

* Add optional argument ``requires_declaration`` so users can decide whether or not ``@ImplementsInterface`` declarations are necessary.

0.4.0 (2019-12-03)
------------------

* Implementations no longer need to explicitly declare that they declare an interface with ``@ImplementsInterface``: the check is done implicitly (and cached) by `AssertImplements` and equivalent functions.

0.3.2 (2019-08-22)
------------------

* Interface and implementation methods can no longer contain mutable defaults, as this is considered
  a bad practice in general.

* ``Null`` instances are now hashable.


0.3.1 (2019-08-16)
------------------

* Fix mismatching signatures when creating "interface stubs" for instances:

  .. code-block:: python

      foo = IFoo(Foo())


0.3.0 (2019-08-08)
------------------

* Interfaces now support keyword-only arguments.

0.2.4 (2019-03-22)
------------------

* Remove ``FunctionNotRegisteredError`` exception, which has not been in use for a few years.


0.2.3 (2019-03-22)
------------------

* Fix issues of ignored exception on nested callback.


0.2.1 (2019-03-14)
------------------

* Fix issues and remove obsolete code.


0.1.8 (2019-03-12)
------------------

* First release on PyPI.

            

Raw data

            {
    "_id": null,
    "home_page": "http://github.com/ESSS/oop-ext",
    "name": "oop-ext",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.10",
    "maintainer_email": null,
    "keywords": "oop_ext",
    "author": "ESSS",
    "author_email": "foss@esss.co",
    "download_url": "https://files.pythonhosted.org/packages/38/c3/885b3c65f0b27c6a317cd1693cbd4ab6a7d83d1ecd239554e314c4165322/oop_ext-2.2.0.tar.gz",
    "platform": null,
    "description": "======================================================================\nOOP Extensions\n======================================================================\n\n.. image:: https://img.shields.io/pypi/v/oop-ext.svg\n    :target: https://pypi.python.org/pypi/oop-ext\n\n.. image:: https://img.shields.io/pypi/pyversions/oop-ext.svg\n    :target: https://pypi.org/project/oop-ext\n\n.. image:: https://github.com/ESSS/oop-ext/workflows/build/badge.svg\n    :target: https://github.com/ESSS/oop-ext/actions\n\n.. image:: https://codecov.io/gh/ESSS/oop-ext/branch/master/graph/badge.svg\n    :target: https://codecov.io/gh/ESSS/oop-ext\n\n.. image:: https://img.shields.io/readthedocs/oop-extensions.svg\n    :target: https://oop-extensions.readthedocs.io/en/latest/\n\n.. image:: https://results.pre-commit.ci/badge/github/ESSS/oop-ext/master.svg\n    :target: https://results.pre-commit.ci/latest/github/ESSS/oop-ext/master\n\n.. image:: https://sonarcloud.io/api/project_badges/measure?project=ESSS_oop-ext&metric=alert_status\n    :target: https://sonarcloud.io/project/overview?id=ESSS_oop-ext\n\n\nWhat is OOP Extensions ?\n================================================================================\n\nOOP Extensions is a set of utilities for object oriented programming which is missing on Python core libraries.\n\nUsage\n================================================================================\n``oop_ext`` brings a set of object oriented utilities, it supports the concept of interfaces,\nabstract/overridable methods and more. ``oop_ext`` carefully checks that implementations\nhave the same method signatures as the interface it implements and raises exceptions otherwise.\n\nHere's a simple example showing some nice features:\n\n.. code-block:: python\n\n    from oop_ext.interface import Interface, ImplementsInterface\n\n\n    class IDisposable(Interface):\n        def dispose(self):\n            \"\"\"\n            Clears this object\n            \"\"\"\n\n        def is_disposed(self) -> bool:\n            \"\"\"\n            Returns True if the object has been cleared\n            \"\"\"\n\n\n    @ImplementsInterface(IDisposable)\n    class MyObject(Disposable):\n        def __init__(self):\n            super().__init__()\n            self._data = [0] * 100\n            self._is_disposed = False\n\n        def is_disposed(self) -> bool:\n            return self._is_disposed\n\n        def dispose(self):\n            self._is_disposed = True\n            self._data = []\n\n\nIf any of the two methods in ``MyObject`` are not implemented or have differ signatures than\nthe ones declared in ``IDisposable``, the ``ImplementsInterface`` decorator will raise an\nerror during import.\n\nArbitrary objects can be verified if they implement a certain interface by using ``IsImplementation``:\n\n.. code-block:: python\n\n    from oop_ext.interface import IsImplementation\n\n    my_object = MyObject()\n    if IsImplementation(my_object, IDisposable):\n        # my_object is guaranteed to implement IDisposable completely\n        my_object.dispose()\n\nAlternatively you can assert that an object implements the desired interface with ``AssertImplements``:\n\n.. code-block:: python\n\n    from oop_ext.interface import AssertImplements\n\n    my_object = MyObject()\n    AssertImplements(my_object, IDisposable)\n    my_object.dispose()\n\n\nType Checking\n-------------\n\nAs of ``1.1.0``, ``oop-ext`` includes inline type annotations and exposes them to user programs.\n\nIf you are running a type checker such as mypy on your tests, you may start noticing type errors indicating incorrect usage.\nIf you run into an error that you believe to be incorrect, please let us know in an issue.\n\nThe types were developed against ``mypy`` version 0.800.\n\nSee `the docs <https://oop-extensions.readthedocs.io/en/latest/interfaces.html#static-type-checking>`__\nfor more information.\n\nContributing\n------------\n\nFor guidance on setting up a development environment and how to make a\ncontribution to oop_ext, see the `contributing guidelines`_.\n\n.. _contributing guidelines: https://github.com/ESSS/oop-ext/blob/master/CONTRIBUTING.rst\n\n\nRelease\n-------\nA reminder for the maintainers on how to make a new release.\n\nNote that the VERSION should follow the semantic versioning as ``X.Y.Z`` (e.g. ``v1.0.5``).\n\n1. Create a ``release-VERSION`` branch from ``upstream/master``.\n2. Update ``CHANGELOG.rst``.\n3. Push a branch with the changes.\n4. Once all builds pass, push a ``VERSION`` tag to ``upstream``.\n5. Merge the PR.\n\n\n2.2.0\n-----\n\n**Release**: 2024-10-24\n\n* ``PriorityCallback`` now has type checking support, similar to ``Callback``, with type checked variants: ``PriorityCallback0``, ``PriorityCallback1``, etc (`#128`_).\n* ``UnregisterContext`` is now public, meant to be used in type annotations.\n* Python 3.10+ is now required.\n\n.. _#128: https://github.com/ESSS/oop-ext/pull/128\n\n2.1.0 (2021-03-19)\n------------------\n\n* #48: New type-checker friendly ``proxy = GetProxy(I, obj)`` function as an alternative to ``proxy = I(obj)``. The\n  latter is not accepted by type checkers in general because interfaces are protocols, which can't be instantiated.\n\n  Also fixed a type-checking error with ``AsssertImplements``::\n\n      Only concrete class can be given where \"Type[Interface]\" is expected\n\n  This happens due to `python/mypy#5374 <https://github.com/python/mypy/issues/5374>`__.\n\n\n2.0.0 (2021-03-10)\n------------------\n\n* #47: Interfaces no longer check type annotations at all.\n\n  It was supported initially, but in practice\n  this feature has shown up to be an impediment to adopting type annotations incrementally, as it\n  discourages adding type annotations to improve existing interfaces, or annotating\n  existing implementations without having to update the interface (and all other implementations\n  by consequence).\n\n  It was decided to let the static type checker correctly deal with matching type annotations, as\n  it can do so more accurately than ``oop-ext`` did before.\n\n1.2.0 (2021-03-09)\n------------------\n\n* #43: Fix support for type annotated ``Attribute`` and ``ReadOnlyAttribute``:\n\n  .. code-block:: python\n\n      class IFoo(Interface):\n          value: int = Attribute(int)\n\n1.1.2 (2021-02-23)\n------------------\n\n* #41: Fix regression introduced in ``1.1.0`` where installing a callback using\n  ``callback.After`` or ``callback.Before`` would make a method no longer compliant with\n  the signature required by its interface.\n\n1.1.1 (2021-02-23)\n------------------\n\n* #38: Reintroduce ``extra_args`` argument to ``Callback._GetKey``, so subclasses can make use\n  of it.\n\n* #36: Fix regression introduced in ``1.1.0`` where ``Abstract`` and ``Implements`` decorators\n  could no longer be used in interfaces implementations.\n\n1.1.0 (2021-02-19)\n------------------\n\n* #25: ``oop-ext`` now includes inline type annotations and exposes them to user programs.\n\n  If you are running a type checker such as mypy on your tests, you may start noticing type errors indicating incorrect usage.\n  If you run into an error that you believe to be incorrect, please let us know in an issue.\n\n  The types were developed against ``mypy`` version 0.800.\n\n* #26: New type-checked ``Callback`` variants, ``Callback0``, ``Callback1``, ``Callback2``, etc, providing\n  type checking for all operations(calling, ``Register``, etc) at nearly zero runtime cost.\n\n  Example:\n\n  .. code-block:: python\n\n      from oop_ext.foundation.callback import Callback2\n\n\n      def changed(x: int, v: float) -> None: ...\n\n\n      on_changed = Callback2[int, float]()\n      on_changed(10, 5.25)\n\n\n* Fixed ``Callbacks.Before`` and ``Callbacks.After`` signatures: previously their signature conveyed\n  that they supported multiple callbacks, but it was a mistake which would break callers because\n  every parameter after the 2nd would be considered the ``sender_as_parameter`` parameter, which\n  was forwarded to ``After`` and ``Before`` functions of the ``_shortcuts.py``\n  module.\n\n1.0.0 (2020-10-01)\n------------------\n\n* ``Callbacks`` can be used as context manager, which provides a ``Register(callback, function)``,\n  which automatically unregisters all functions when the context manager ends.\n\n* ``Callback.Register(function)`` now returns an object with a ``Unregister()`` method, which\n  can be used to undo the register call.\n\n0.6.0 (2020-01-31)\n==================\n\n* Change back the default value of ``requires_declaration`` to ``True`` and fix an error (#22) where the cache wasn't properly cleared.\n\n0.5.1 (2019-12-20)\n------------------\n\n* Fixes an issue (#20) where mocked `classmethods` weren't considered a valid method during internal checks.\n\n0.5.0 (2019-12-12)\n------------------\n\n* Add optional argument ``requires_declaration`` so users can decide whether or not ``@ImplementsInterface`` declarations are necessary.\n\n0.4.0 (2019-12-03)\n------------------\n\n* Implementations no longer need to explicitly declare that they declare an interface with ``@ImplementsInterface``: the check is done implicitly (and cached) by `AssertImplements` and equivalent functions.\n\n0.3.2 (2019-08-22)\n------------------\n\n* Interface and implementation methods can no longer contain mutable defaults, as this is considered\n  a bad practice in general.\n\n* ``Null`` instances are now hashable.\n\n\n0.3.1 (2019-08-16)\n------------------\n\n* Fix mismatching signatures when creating \"interface stubs\" for instances:\n\n  .. code-block:: python\n\n      foo = IFoo(Foo())\n\n\n0.3.0 (2019-08-08)\n------------------\n\n* Interfaces now support keyword-only arguments.\n\n0.2.4 (2019-03-22)\n------------------\n\n* Remove ``FunctionNotRegisteredError`` exception, which has not been in use for a few years.\n\n\n0.2.3 (2019-03-22)\n------------------\n\n* Fix issues of ignored exception on nested callback.\n\n\n0.2.1 (2019-03-14)\n------------------\n\n* Fix issues and remove obsolete code.\n\n\n0.1.8 (2019-03-12)\n------------------\n\n* First release on PyPI.\n",
    "bugtrack_url": null,
    "license": "MIT license",
    "summary": "OOP Extensions is a set of utilities for object oriented programming not found on Python's standard library.",
    "version": "2.2.0",
    "project_urls": {
        "Homepage": "http://github.com/ESSS/oop-ext"
    },
    "split_keywords": [
        "oop_ext"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "29ff184e538a537639c849b7a050b53a79b016ced7a9d6a3df4443bb60ec25c4",
                "md5": "2b76b5914cb2d393ccf9f5fc0240649f",
                "sha256": "1fdead59140f8681b2b643cd33efef7cde7c9b78264e7176a71527090cc694dd"
            },
            "downloads": -1,
            "filename": "oop_ext-2.2.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "2b76b5914cb2d393ccf9f5fc0240649f",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.10",
            "size": 73930,
            "upload_time": "2024-10-24T12:20:37",
            "upload_time_iso_8601": "2024-10-24T12:20:37.984642Z",
            "url": "https://files.pythonhosted.org/packages/29/ff/184e538a537639c849b7a050b53a79b016ced7a9d6a3df4443bb60ec25c4/oop_ext-2.2.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "38c3885b3c65f0b27c6a317cd1693cbd4ab6a7d83d1ecd239554e314c4165322",
                "md5": "37c7185271d604de8cc282ada0ce5784",
                "sha256": "266f5bdcb8ad9f44e3395826f60540c2e7da7710b9f0d6d721037869d1daa992"
            },
            "downloads": -1,
            "filename": "oop_ext-2.2.0.tar.gz",
            "has_sig": false,
            "md5_digest": "37c7185271d604de8cc282ada0ce5784",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.10",
            "size": 78407,
            "upload_time": "2024-10-24T12:20:39",
            "upload_time_iso_8601": "2024-10-24T12:20:39.819139Z",
            "url": "https://files.pythonhosted.org/packages/38/c3/885b3c65f0b27c6a317cd1693cbd4ab6a7d83d1ecd239554e314c4165322/oop_ext-2.2.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-10-24 12:20:39",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "ESSS",
    "github_project": "oop-ext",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "tox": true,
    "lcname": "oop-ext"
}
        
Elapsed time: 1.39243s