classoptions 0.2.0
Implement namespaced and inheritable metadata at the class level.
Requires Python: >=3.6

## Description
Implement namespaced and inheritable metadata at the class level.

Inspired on Meta classes from Django models and Django Rest Framework model serializers.

## Quick Start
### Installation
`pip install classoptions`

### Simple inheritance
```python
from classoptions import ClassOptionsMetaclass
from typing import Any

class Pizza(metaclass=ClassOptionsMetaclass):
    _meta: Any
    
    class DefaultMeta:
        client_can_modify = True
        notes = None

    cooking_temp = 400
    cooking_time = 1    

class HawaiianPizza(Pizza):
    ingredients = ["cheese", "ham", "pineapple"]
    
    class Meta:
        notes = "Do not judge the costumer."
        private_note = "If planning a party, ask first if people like it."
        
print("Hawaiian Pizza:")
print("Ingredients:", ", ".join(HawaiianPizza.ingredients))
print("Cooking Temperature (F):", HawaiianPizza.cooking_temp)
print("Cooking Time (hours):", HawaiianPizza.cooking_time)
print("Client can modify:", HawaiianPizza._meta.client_can_modify)
print("Notes:")
print(HawaiianPizza._meta.notes)
print("Private Note:")
print(HawaiianPizza._meta.private_note)
```
Outputs:
```text
Hawaiian Pizza:
Ingredients: cheese, ham, pineapple
Cooking Temperature (F): 400
Cooking Time (hours): 1
Client can modify: True
Notes:
Do not judge the costumer.
Private Note:
If planning a party, ask first if people like it.
```

### Multiple Inheritance
Works similar to python inheritance, except we don't need to explicitly inherit from the parent class.

```python
from classoptions import ClassOptionsMetaclass
from typing import Any

class A(metaclass=ClassOptionsMetaclass):
    _meta: Any
    class DefaultMeta:
        color = "red"
        size = 2
        hello = "world"
        i_like_pizza = True

class B(A):
    class DefaultMeta:
        color = "blue"
        size = 3

class C(B):
    class Meta:
        size = 4  # Specific to C only

class D(A):
    class DefaultMeta:
        color = "black"
        hello = "country"

class E(D, C):
    class Meta:
        i_like_hawaiian_pizza = "maybe"

print("E custom meta")
print("i_like_hawaiian_pizza:", E._meta.i_like_hawaiian_pizza)

print("\nInherited from B")
print("size:", E._meta.size)

print("\nInherited from D")
print("color:", E._meta.color)
print("hello:", E._meta.hello)

print("\nInherited from A")
print("i_like_pizza:", E._meta.i_like_pizza)
```
Outputs:
```text
E custom meta
i_like_hawaiian_pizza: maybe

Inherited from B
size: 3

Inherited from D
color: black
hello: country

Inherited from A
i_like_pizza: True
```

### Using other class/attribute names
With ``ClassOptionsMetaclass.factory`` you can overwrite how you define default metadata, class specific metadata,
and how you access the result.

```python
from classoptions import ClassOptionsMetaclass
from typing import Any

class A(metaclass=ClassOptionsMetaclass.factory("Options", "DefaultOptions", "_options")):
    _options: Any
    
    class DefaultOptions:
        color = "red"
        size = 2

    cooking_temp = 400
    cooking_time = 1    

class B(A):
    class Options:
        color = "blue"
        
print("B color:", B._options.color)
print("B size:", B._options.size)
```
Outputs:
```text
B color: blue
B size: 2
```

## License
MIT License.