oopy 1.0.2
Small helper library for object-oriented python programming
License: MIT
Requires Python: >=3.8,<4.0

# OOPy: small helper library for object-oriented python programming

OOPy is a library that aims to help with object oriented programming in python. The library has no further dependencies, type hints are used throughout the project, and the tests have 100% code coverage.

One of the main reasons why I started this library is that I wanted some convenient decorator for common use-cases, such as singleton pattern or to slot a class, and I wanted to explore meta-programming with python.

The library is currently under development, therefore it has only a small functionality. Feel free to open some tickets with things that you want to have included.

> **NOTE**: This library relies heavily on meta-programming and dynamically adding properties at runtime.

# Installation

To install this package you need Python 3.8 or newer:

```shell
pip install oopy
```

## Creational Patterns

In this part we explain the functionality of some creational patterns that are build into this library.

### Singleton

Although the singleton pattern is often considered bad practice, it can have its use-cases. I wanted to simplify the usage to a single decorator without having to rely on implementing it myself over and over again, or use inheritance. 

Usage:

```python
from oopy import singleton


@singleton
class MyClass:

    def __init__(self) -> None:
        ...
```

It's usage is straightforward, just import the singleton decorator from the main package and annotate your class, now only a single object will be created at a time, even when calling the constructor multiple times. This is done by dyniamically binding the instance to a variable called `self.__instance` and overwriting the `__new__` function of the class. 

If you want to bind the instance to another variable name you can pass the name to the decorator:

```python

@singleton(bind_property='name_of_property')
class MyClass:

    def __init__(self) -> None:
        ...
```

> **NOTE**: The singleton decorator is not compatible with the `Slotted` meta-class (see further down)


### Borg

The Borg pattern is often times referred to as the more pythonic approach of the singleton pattern (see [here](https://www.oreilly.com/library/view/python-cookbook/0596001673/ch05s23.html) for a short description). It differs insofar that with the singleton pattern only a single instance is created, while objects with the borg pattern share only the state although being different objects.

Usage:

```python
from oopy import Borg

class MyClass(Borg):

    def __init__(self) -> None:
        ...
```


### Slotted

In some use-cases it might make sense to slot a class, but this can oftentimes be tedious, especially if the class a lots of properties. Therefore, this package contains a meta-class named `Slotted` that infers all properties within the `__init__` function and adds them to the `__slots__` collection of the class.

Usage:

```python
from oopy import Slotted

class MyClass(metaclass=Slotted):

    def __init__(self) -> None:
        self.this_will_be_slotted = 'foo'
        self._this_will_also_be_slotted = 'bar'
        self.__and_so_does_this = 'foo bar'
```

As you can see it does not make any difference if the property is underscored, or double-underscored, all properties will be added to `__slots__`.


## Error Handling

OOPy provides a `catch_error`-decorator which can be used on a function to catch a specific error and return some value from the function if the error occurs. This can be used to return default values in an error case without using a try-catch block.

Usage:

```python
from oopy import catch_error

@catch_error(AttributeError, 'This will be returned in error case')
def throws_error() -> str:
    raise AttributeError
```