|
| 1 | +# Odin |
| 2 | + |
| 3 | +Odin provides a declarative framework for defining resources (classes) and their relationships, validation of the fields |
| 4 | +that make up the resources and mapping between objects (either a resource, or other python structures). |
| 5 | + |
| 6 | +Odin also comes with built in serialisation tools for importing and exporting data from resources. |
| 7 | + |
| 8 | +<table> |
| 9 | +<tr> |
| 10 | + <th>Docs/Help</th> |
| 11 | + <td> |
| 12 | + <a href="https://odin.readthedocs.org/"> |
| 13 | + <img src="https://readthedocs.org/projects/odin/badge/?version=latest" |
| 14 | + alt="ReadTheDocs" /> |
| 15 | + </a> |
| 16 | + <a href="https://gitter.im/timsavage/odin"> |
| 17 | + <img src="https://img.shields.io/badge/gitterim-timsavage.odin-brightgreen.svg?style=flat " |
| 18 | + alt="Gitter.im" /> |
| 19 | + </a> |
| 20 | + </td> |
| 21 | +</tr> |
| 22 | +<tr> |
| 23 | + <th>Build</th> |
| 24 | + <td> |
| 25 | + <a href="https://github.com/python-odin/odin/actions/workflows/release.yml"> |
| 26 | + <img src="https://github.com/python-odin/odin/actions/workflows/release.yml/badge.svg" |
| 27 | + alt="Python package" /> |
| 28 | + </a> |
| 29 | + </td> |
| 30 | +</tr> |
| 31 | +<tr> |
| 32 | + <th>Quality</th> |
| 33 | + <td> |
| 34 | + <a href="https://sonarcloud.io/dashboard?id=python-odin_odin"> |
| 35 | + <img src="https://sonarcloud.io/api/project_badges/measure?project=python-odin_odin&metric=sqale_rating" |
| 36 | + alt="Maintainability" /> |
| 37 | + </a> |
| 38 | + <a href="https://sonarcloud.io/project/security_hotspots"> |
| 39 | + <img src="https://sonarcloud.io/api/project_badges/measure?project=python-odin_odin&metric=security_rating" |
| 40 | + alt="Security" /> |
| 41 | + </a> |
| 42 | + <a href="https://sonarcloud.io/code?id=python-odin_odin"> |
| 43 | + <img src="https://sonarcloud.io/api/project_badges/measure?project=python-odin_odin&metric=coverage" |
| 44 | + alt="Coverage" /> |
| 45 | + </a> |
| 46 | + <a href="https://github.com/ambv/black"> |
| 47 | + <img src="https://img.shields.io/badge/code%20style-black-000000.svg" |
| 48 | + alt="Once you go Black..." /> |
| 49 | + </a> |
| 50 | + </td> |
| 51 | +</tr> |
| 52 | +<tr> |
| 53 | + <th>Package</th> |
| 54 | + <td> |
| 55 | + <a href="https://pypi.io/pypi/odin/"> |
| 56 | + <img src="https://img.shields.io/pypi/v/odin" |
| 57 | + alt="Latest Version" /> |
| 58 | + </a> |
| 59 | + <a href="https://pypi.io/pypi/odin/"> |
| 60 | + <img src="https://img.shields.io/pypi/pyversions/odin" /> |
| 61 | + </a> |
| 62 | + <a href="https://pypi.io/pypi/odin/"> |
| 63 | + <img src="https://img.shields.io/pypi/l/odin" /> |
| 64 | + </a> |
| 65 | + <a href="https://pypi.io/pypi/odin/"> |
| 66 | + <img src="https://img.shields.io/pypi/wheel/odin" |
| 67 | + alt="PyPI - Wheel" /> |
| 68 | + </a> |
| 69 | + </td> |
| 70 | +</tr> |
| 71 | +</table> |
| 72 | + |
| 73 | +## Highlights |
| 74 | + |
| 75 | +* Class based declarative style |
| 76 | +* Class based annotations style! ✨ new in 2.0 |
| 77 | +* Fields for building composite resources |
| 78 | +* Field and Resource level validation |
| 79 | +* Easy extension to support custom fields |
| 80 | +* Python 3.8+ and PyPy <sup>1</sup> supported |
| 81 | +* Support for documenting resources with [Sphinx](http://sphinx-doc.org/) |
| 82 | +* Minimal dependencies |
| 83 | + |
| 84 | +<sup>1</sup> certain contrib items are not supported. Pint is not installable with PyPy. |
| 85 | + |
| 86 | +## Use cases |
| 87 | + |
| 88 | +* Design, document and validate complex (and simple!) data structures |
| 89 | +* Convert structures to and from different formats such as JSON, YAML, MsgPack, CSV, TOML |
| 90 | +* Validate API inputs |
| 91 | +* Define message formats for communications protocols, like an RPC |
| 92 | +* Map API requests to ORM objects |
| 93 | + |
| 94 | +## Quick links |
| 95 | + |
| 96 | +* [Documentation](https://odin.readthedocs.org/) |
| 97 | +* [Project home](https://github.com/python-odin/odin) |
| 98 | +* [Issue tracker](https://github.com/python-odin/odin/issues) |
| 99 | + |
| 100 | + |
| 101 | +## Upcoming features |
| 102 | + |
| 103 | +### In development |
| 104 | + |
| 105 | +* XML Codec (export only) |
| 106 | +* Complete documentation coverage |
| 107 | +* Improvements for CSV Codec (writing, reading multi resource CSV's) |
| 108 | + |
| 109 | + |
| 110 | +## Requires |
| 111 | + |
| 112 | +### Optional |
| 113 | + |
| 114 | +* simplejson - Odin will use simplejson if it is available or fallback to the builtin json library |
| 115 | +* msgpack-python - To enable use of the msgpack codec |
| 116 | +* pyyaml - To enable use of the YAML codec |
| 117 | +* toml - To enable use of the TOML codec |
| 118 | + |
| 119 | +### Contrib |
| 120 | + |
| 121 | +* arrow - Support for Arrow data types. |
| 122 | +* pint - Support for physical quantities using the [Pint](http://pint.readthedocs.org/) library. |
| 123 | + |
| 124 | +### Development |
| 125 | + |
| 126 | +* pytest - Testing |
| 127 | +* pytest-cov - Coverage reporting |
| 128 | + |
| 129 | +## Example |
| 130 | + |
| 131 | +### Definition |
| 132 | + |
| 133 | +```python |
| 134 | +import odin |
| 135 | + |
| 136 | +class Author(odin.Resource): |
| 137 | + name = odin.StringField() |
| 138 | + |
| 139 | +class Publisher(odin.Resource): |
| 140 | + name = odin.StringField() |
| 141 | + |
| 142 | +class Book(odin.Resource): |
| 143 | + title = odin.StringField() |
| 144 | + authors = odin.ArrayOf(Author) |
| 145 | + publisher = odin.DictAs(Publisher) |
| 146 | + genre = odin.StringField() |
| 147 | + num_pages = odin.IntegerField() |
| 148 | +``` |
| 149 | + |
| 150 | +### Using Annotations |
| 151 | + |
| 152 | +```python |
| 153 | +import odin |
| 154 | + |
| 155 | +class Author(odin.AnnotatedResource): |
| 156 | + name: str |
| 157 | + |
| 158 | +class Publisher(odin.AnnotatedResource): |
| 159 | + name: str |
| 160 | + website: odin.Url | None |
| 161 | + |
| 162 | +class Book(odin.AnnotatedResource): |
| 163 | + title: str |
| 164 | + authors: list[Author] |
| 165 | + publisher: Publisher |
| 166 | + genre: str |
| 167 | + num_pages: int |
| 168 | +``` |
| 169 | + |
| 170 | +### Usage |
| 171 | + |
| 172 | +```pycon |
| 173 | +>>> b = Book( |
| 174 | + title="Consider Phlebas", |
| 175 | + genre="Space Opera", |
| 176 | + publisher=Publisher(name="Macmillan"), |
| 177 | + num_pages=471 |
| 178 | + ) |
| 179 | +>>> b.authors.append(Author(name="Iain M. Banks")) |
| 180 | +>>> from odin.codecs import json_codec |
| 181 | +>>> json_codec.dumps(b, indent=4) |
| 182 | +{ |
| 183 | + "$": "Book", |
| 184 | + "authors": [ |
| 185 | + { |
| 186 | + "$": "Author", |
| 187 | + "name": "Iain M. Banks" |
| 188 | + } |
| 189 | + ], |
| 190 | + "genre": "Space Opera", |
| 191 | + "num_pages": 471, |
| 192 | + "publisher": { |
| 193 | + "$": "Publisher", |
| 194 | + "name": "Macmillan" |
| 195 | + }, |
| 196 | + "title": "Consider Phlebas" |
| 197 | +} |
| 198 | +``` |
0 commit comments