Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/dry-python/classes
Smart, pythonic, ad-hoc, typed polymorphism for Python
https://github.com/dry-python/classes
fp mypy mypy-plugins mypy-stubs pep561 python python3 typeclasses typesafety
Last synced: 8 days ago
JSON representation
Smart, pythonic, ad-hoc, typed polymorphism for Python
- Host: GitHub
- URL: https://github.com/dry-python/classes
- Owner: dry-python
- License: bsd-2-clause
- Created: 2019-10-25T22:14:08.000Z (about 5 years ago)
- Default Branch: master
- Last Pushed: 2024-09-23T14:51:50.000Z (about 2 months ago)
- Last Synced: 2024-10-29T20:23:06.759Z (15 days ago)
- Topics: fp, mypy, mypy-plugins, mypy-stubs, pep561, python, python3, typeclasses, typesafety
- Language: Python
- Homepage: https://classes.rtfd.io
- Size: 1.05 MB
- Stars: 665
- Watchers: 15
- Forks: 24
- Open Issues: 32
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
Awesome Lists containing this project
README
# classes
[![classes logo](https://raw.githubusercontent.com/dry-python/brand/master/logo/classes.png)](https://github.com/dry-python/classes)
-----
[![Build Status](https://travis-ci.org/dry-python/classes.svg?branch=master)](https://travis-ci.org/dry-python/classes)
[![codecov](https://codecov.io/gh/dry-python/classes/branch/master/graph/badge.svg)](https://codecov.io/gh/dry-python/classes)
[![Documentation Status](https://readthedocs.org/projects/classes/badge/?version=latest)](https://classes.readthedocs.io/en/latest/?badge=latest)
[![Python Version](https://img.shields.io/pypi/pyversions/classes.svg)](https://pypi.org/project/classes/)
[![wemake-python-styleguide](https://img.shields.io/badge/style-wemake-000000.svg)](https://github.com/wemake-services/wemake-python-styleguide)
[![Telegram chat](https://img.shields.io/badge/chat-join-blue?logo=telegram)](https://t.me/drypython)-----
Smart, pythonic, ad-hoc, typed polymorphism for Python.
## Features
- Provides a bunch of primitives to write declarative business logic
- Enforces better architecture
- Fully typed with annotations and checked with `mypy`, [PEP561 compatible](https://www.python.org/dev/peps/pep-0561/)
- Allows to write a lot of simple code without inheritance or interfaces
- Pythonic and pleasant to write and to read (!)
- Easy to start: has lots of docs, tests, and tutorials## Installation
```bash
pip install classes
```You also need to [configure](https://classes.readthedocs.io/en/latest/pages/container.html#type-safety)
`mypy` correctly and install our plugin:```ini
# In setup.cfg or mypy.ini:
[mypy]
plugins =
classes.contrib.mypy.classes_plugin
```**Without this step**, your project will report type-violations here and there.
We also recommend to use the same `mypy` settings [we use](https://github.com/wemake-services/wemake-python-styleguide/blob/master/styles/mypy.toml).
Make sure you know how to get started, [check out our docs](https://classes.readthedocs.io/en/latest/)!
## Example
Imagine, that you want to bound implementation to some particular type.
Like, strings behave like this, numbers behave like that, and so on.The good realworld example is `djangorestframework`.
It is build around the idea that different
data types should be converted differently to and from `json` format.What is the "traditional" (or outdated if you will!) approach?
To create tons of classes for different data types and use them.That's how we end up with classes like so:
```python
class IntField(Field):
def from_json(self, value):
return valuedef to_json(self, value):
return value
```It literally has a lot of problems:
- It is hard to type this code. How can I be sure that my `json` is parseable by the given schema?
- It produces a lot of boilerplate
- It has complex API: there are usually several methods to override, some fields to adjust. Moreover, we use a class, not a simple function
- It is hard to extend the default library for new custom types you will have in your own project
- It is hard to overrideThere should be a better way of solving this problem!
And typeclasses are a better way!How would new API look like with this concept?
```python
>>> from typing import Union
>>> from classes import typeclass>>> @typeclass
... def to_json(instance) -> str:
... """This is a typeclass definition to convert things to json.""">>> @to_json.instance(int)
... @to_json.instance(float)
... def _to_json_int(instance: Union[int, float]) -> str:
... return str(instance)>>> @to_json.instance(bool)
... def _to_json_bool(instance: bool) -> str:
... return 'true' if instance else 'false'>>> @to_json.instance(list)
... def _to_json_list(instance: list) -> str:
... return '[{0}]'.format(
... ', '.join(to_json(list_item) for list_item in instance),
... )```
See how easy it is to works with types and implementation?
Typeclass is represented as a regular function, so you can use it like one:
```python
>>> to_json(True)
'true'
>>> to_json(1)
'1'
>>> to_json([False, 1, 2.5])
'[false, 1, 2.5]'```
And it is easy to extend this typeclass with your own classes as well:
```python
# Pretending to import the existing library from somewhere:
# from to_json import to_json>>> import datetime as dt
>>> @to_json.instance(dt.datetime)
... def _to_json_datetime(instance: dt.datetime) -> str:
... return instance.isoformat()>>> to_json(dt.datetime(2019, 10, 31, 12, 28, 00))
'2019-10-31T12:28:00'```
That's how simple, safe, and powerful typeclasses are!
Make sure to [check out our full docs](https://classes.readthedocs.io) to learn more.## More!
Want more? [Go to the docs!](https://classes.readthedocs.io) Or read these articles:
- [Typeclasses in Python](https://sobolevn.me/2021/06/typeclasses-in-python)— ⭐️ —
Drylabs maintains dry-python and helps those who want to use it inside their organizations.
Read more in our Telegram group