{"id":13468464,"url":"https://github.com/dry-python/classes","last_synced_at":"2025-05-14T09:12:19.152Z","repository":{"id":36583919,"uuid":"217621930","full_name":"dry-python/classes","owner":"dry-python","description":"Smart, pythonic, ad-hoc, typed polymorphism for Python","archived":false,"fork":false,"pushed_at":"2024-12-17T05:48:30.000Z","size":902,"stargazers_count":702,"open_issues_count":37,"forks_count":27,"subscribers_count":14,"default_branch":"master","last_synced_at":"2025-05-08T16:39:38.707Z","etag":null,"topics":["fp","mypy","mypy-plugins","mypy-stubs","pep561","python","python3","typeclasses","typesafety"],"latest_commit_sha":null,"homepage":"https://classes.rtfd.io","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-2-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dry-python.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":"dry-python","open_collective":"dry-python","custom":"https://boosty.to/sobolevn"}},"created_at":"2019-10-25T22:14:08.000Z","updated_at":"2025-04-22T14:42:41.000Z","dependencies_parsed_at":"2023-02-16T07:45:22.142Z","dependency_job_id":"e3cfa417-bff0-4e52-87b7-f69cc02931bb","html_url":"https://github.com/dry-python/classes","commit_stats":{"total_commits":360,"total_committers":16,"mean_commits":22.5,"dds":0.6638888888888889,"last_synced_commit":"0b958c838ee8ee683c9855cdc770a27bde29dd67"},"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dry-python%2Fclasses","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dry-python%2Fclasses/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dry-python%2Fclasses/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dry-python%2Fclasses/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dry-python","download_url":"https://codeload.github.com/dry-python/classes/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253857940,"owners_count":21974838,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["fp","mypy","mypy-plugins","mypy-stubs","pep561","python","python3","typeclasses","typesafety"],"created_at":"2024-07-31T15:01:11.431Z","updated_at":"2025-05-14T09:12:19.091Z","avatar_url":"https://github.com/dry-python.png","language":"Python","readme":"# classes\n\n[![classes logo](https://raw.githubusercontent.com/dry-python/brand/master/logo/classes.png)](https://github.com/dry-python/classes)\n\n-----\n\n[![Build Status](https://travis-ci.org/dry-python/classes.svg?branch=master)](https://travis-ci.org/dry-python/classes)\n[![codecov](https://codecov.io/gh/dry-python/classes/branch/master/graph/badge.svg)](https://codecov.io/gh/dry-python/classes)\n[![Documentation Status](https://readthedocs.org/projects/classes/badge/?version=latest)](https://classes.readthedocs.io/en/latest/?badge=latest)\n[![Python Version](https://img.shields.io/pypi/pyversions/classes.svg)](https://pypi.org/project/classes/)\n[![wemake-python-styleguide](https://img.shields.io/badge/style-wemake-000000.svg)](https://github.com/wemake-services/wemake-python-styleguide)\n[![Telegram chat](https://img.shields.io/badge/chat-join-blue?logo=telegram)](https://t.me/drypython)\n\n-----\n\nSmart, pythonic, ad-hoc, typed polymorphism for Python.\n\n\n## Features\n\n- Provides a bunch of primitives to write declarative business logic\n- Enforces better architecture\n- Fully typed with annotations and checked with `mypy`, [PEP561 compatible](https://www.python.org/dev/peps/pep-0561/)\n- Allows to write a lot of simple code without inheritance or interfaces\n- Pythonic and pleasant to write and to read (!)\n- Easy to start: has lots of docs, tests, and tutorials\n\n\n## Installation\n\n```bash\npip install classes\n```\n\nYou also need to [configure](https://classes.readthedocs.io/en/latest/pages/container.html#type-safety)\n`mypy` correctly and install our plugin:\n\n```ini\n# In setup.cfg or mypy.ini:\n[mypy]\nplugins =\n  classes.contrib.mypy.classes_plugin\n```\n\n**Without this step**, your project will report type-violations here and there.\n\nWe also recommend to use the same `mypy` settings [we use](https://github.com/wemake-services/wemake-python-styleguide/blob/master/styles/mypy.toml).\n\nMake sure you know how to get started, [check out our docs](https://classes.readthedocs.io/en/latest/)!\n\n\n## Example\n\nImagine, that you want to bind implementation to some particular type.\nLike, strings behave like this, numbers behave like that, and so on.\n\nThe good realworld example is `djangorestframework`.\nIt is built around the idea that different\ndata types should be converted differently to and from `json` format.\n\nWhat is the \"traditional\" (or outdated if you will!) approach?\nTo create tons of classes for different data types and use them.\n\nThat's how we end up with classes like so:\n\n```python\nclass IntField(Field):\n    def from_json(self, value):\n        return value\n\n    def to_json(self, value):\n        return value\n```\n\nIt literally has a lot of problems:\n\n- It is hard to type this code. How can I be sure that my `json` is parseable by the given schema?\n- It produces a lot of boilerplate\n- It has complex API: there are usually several methods to override, some fields to adjust. Moreover, we use a class, not a simple function\n- It is hard to extend the default library for new custom types you will have in your own project\n- It is hard to override\n\nThere should be a better way of solving this problem!\nAnd typeclasses are a better way!\n\nHow would new API look like with this concept?\n\n```python\n\u003e\u003e\u003e from typing import Union\n\u003e\u003e\u003e from classes import typeclass\n\n\u003e\u003e\u003e @typeclass\n... def to_json(instance) -\u003e str:\n...     \"\"\"This is a typeclass definition to convert things to json.\"\"\"\n\n\u003e\u003e\u003e @to_json.instance(int)\n... @to_json.instance(float)\n... def _to_json_int(instance: Union[int, float]) -\u003e str:\n...     return str(instance)\n\n\u003e\u003e\u003e @to_json.instance(bool)\n... def _to_json_bool(instance: bool) -\u003e str:\n...     return 'true' if instance else 'false'\n\n\u003e\u003e\u003e @to_json.instance(list)\n... def _to_json_list(instance: list) -\u003e str:\n...     return '[{0}]'.format(\n...         ', '.join(to_json(list_item) for list_item in instance),\n...     )\n\n```\n\nSee how easy it is to work with types and implementation?\n\nTypeclass is represented as a regular function, so you can use it like one:\n\n```python\n\u003e\u003e\u003e to_json(True)\n'true'\n\u003e\u003e\u003e to_json(1)\n'1'\n\u003e\u003e\u003e to_json([False, 1, 2.5])\n'[false, 1, 2.5]'\n\n```\n\nAnd it is easy to extend this typeclass with your own classes as well:\n\n```python\n# Pretending to import the existing library from somewhere:\n# from to_json import to_json\n\n\u003e\u003e\u003e import datetime as dt\n\n\u003e\u003e\u003e @to_json.instance(dt.datetime)\n... def _to_json_datetime(instance: dt.datetime) -\u003e str:\n...     return instance.isoformat()\n\n\u003e\u003e\u003e to_json(dt.datetime(2019, 10, 31, 12, 28, 00))\n'2019-10-31T12:28:00'\n\n```\n\nThat's how simple, safe, and powerful typeclasses are!\nMake sure to [check out our full docs](https://classes.readthedocs.io) to learn more.\n\n\n## More!\n\nWant more? [Go to the docs!](https://classes.readthedocs.io) Or read these articles:\n- [Typeclasses in Python](https://sobolevn.me/2021/06/typeclasses-in-python)\n\n\n\u003cp align=\"center\"\u003e\u0026mdash; ⭐️ \u0026mdash;\u003c/p\u003e\n\u003cp align=\"center\"\u003e\u003ci\u003eDrylabs maintains dry-python and helps those who want to use it inside their organizations.\u003c/i\u003e\u003c/p\u003e\n\u003cp align=\"center\"\u003e\u003ci\u003eRead more in \u003ca href=\"https://t.me/drypython\"\u003eour Telegram group\u003ca\u003e\u003c/i\u003e\u003c/p\u003e\n","funding_links":["https://github.com/sponsors/dry-python","https://opencollective.com/dry-python","https://boosty.to/sobolevn"],"categories":["Python","Awesome Functional Python"],"sub_categories":["Libraries"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdry-python%2Fclasses","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdry-python%2Fclasses","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdry-python%2Fclasses/lists"}