Skip to main content

OOP Extensions is a set of utilities for object oriented programming not found on Python's standard library.

Project description

https://img.shields.io/pypi/v/oop-ext.svg https://img.shields.io/pypi/pyversions/oop-ext.svg https://github.com/ESSS/oop-ext/workflows/build/badge.svg https://codecov.io/gh/ESSS/oop-ext/branch/master/graph/badge.svg https://img.shields.io/readthedocs/oop-extensions.svg https://results.pre-commit.ci/badge/github/ESSS/oop-ext/master.svg https://sonarcloud.io/api/project_badges/measure?project=ESSS_oop-ext&metric=alert_status

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:

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:

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:

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 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.

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.

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.

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:

    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:

    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:

    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.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

oop_ext-2.2.0.tar.gz (78.4 kB view details)

Uploaded Source

Built Distribution

oop_ext-2.2.0-py3-none-any.whl (73.9 kB view details)

Uploaded Python 3

File details

Details for the file oop_ext-2.2.0.tar.gz.

File metadata

  • Download URL: oop_ext-2.2.0.tar.gz
  • Upload date:
  • Size: 78.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.1 CPython/3.12.7

File hashes

Hashes for oop_ext-2.2.0.tar.gz
Algorithm Hash digest
SHA256 266f5bdcb8ad9f44e3395826f60540c2e7da7710b9f0d6d721037869d1daa992
MD5 37c7185271d604de8cc282ada0ce5784
BLAKE2b-256 38c3885b3c65f0b27c6a317cd1693cbd4ab6a7d83d1ecd239554e314c4165322

See more details on using hashes here.

File details

Details for the file oop_ext-2.2.0-py3-none-any.whl.

File metadata

  • Download URL: oop_ext-2.2.0-py3-none-any.whl
  • Upload date:
  • Size: 73.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.1 CPython/3.12.7

File hashes

Hashes for oop_ext-2.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 1fdead59140f8681b2b643cd33efef7cde7c9b78264e7176a71527090cc694dd
MD5 2b76b5914cb2d393ccf9f5fc0240649f
BLAKE2b-256 29ff184e538a537639c849b7a050b53a79b016ced7a9d6a3df4443bb60ec25c4

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page