# -*- coding: utf-8 -*-
from setuptools import setup

packages = \
['odmantic']

package_data = \
{'': ['*']}

install_requires = \
['motor>=2.1.0,<2.6.0',
 'pydantic>=1.6.2,!=1.7,!=1.7.1,!=1.7.2,!=1.7.3,!=1.8,!=1.8.1,<1.9.0']

extras_require = \
{':python_version < "3.8"': ['importlib-metadata>=1,<5',
                             'typing-extensions>=3.7.4.3,<4.0.0.0'],
 'fastapi': ['fastapi>=0.61.1,<0.67.0']}

setup_kwargs = {
    'name': 'odmanticti',
    'version': '0.3.6rc2',
    'description': 'ODMantic, an AsyncIO MongoDB Object Document Mapper for Python using type hints ',
    'long_description': '<div align="center">\n<h1>ODMantic</h1>\n<a href="https://github.com/art049/odmantic/actions?query=workflow%3A%22build%22+branch%3Amaster" target="_blank">\n    <img src="https://github.com/art049/odmantic/workflows/build/badge.svg" alt="build">\n</a>\n<a href="https://codecov.io/gh/art049/odmantic" target="_blank">\n    <img src="https://codecov.io/gh/art049/odmantic/branch/master/graph/badge.svg?token=3NYZK14STZ" alt="coverage">\n</a>\n<img src="https://img.shields.io/badge/python-3.6%20|%203.7%20|%203.8%20|%203.9-informational.svg" alt="python-3.6-3.7-3.8">\n<a href="https://pypi.org/project/odmantic" target="_blank">\n    <img src="https://img.shields.io/pypi/v/odmantic?color=%2334D058&label=pypi" alt="Package version">\n</a>\n<a href="https://gitter.im/odmantic/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge" target="_blank">\n    <img src="https://badges.gitter.im/odmantic/community.svg" alt="Gitter">\n</a>\n\n</div>\n\n---\n\n**Documentation**: [https://art049.github.io/odmantic/](https://art049.github.io/odmantic/)\n\n> This version has been updated to support motor 2.5+ (and therefore python 3.9 and mongo v5.)\n\n---\n\nAsynchronous ODM (Object Document Mapper) for <a href="https://www.mongodb.com/"\ntarget="_blank">MongoDB</a> based on standard python type hints. It\'s built on top of <a\nhref="https://pydantic-docs.helpmanual.io/" target="_blank">pydantic</a> for model\ndefinition and validation.\n\nCore features:\n\n- **Simple**: define your model by typing your fields using python types, build queries\n  using python comparison operators\n\n- **Developer experience**: field/method autocompletion, type hints, data validation,\n  perform database operations with a functional API\n\n- **Fully typed**: leverage static analysis to reduce runtime issues\n\n- **AsyncIO**: works well with ASGI frameworks (<a href="https://fastapi.tiangolo.com/"\n  target="_blank">FastAPI</a>, <a href="https://pgjones.gitlab.io/quart/"\n  target="_blank">quart</a>, <a href="https://sanicframework.org/"\n  target="_blank">sanic</a>, <a href="https://www.starlette.io/"\n  target="_blank">Starlette</a>, ...)\n\n- **Serialization**: built in JSON serialization and JSON schema generation\n\n## Requirements\n\n**Python**: 3.6 and later (tested against 3.6, 3.7, 3.8 and 3.9)\n\n**MongoDB**: 4.0 and later\n\nTwo direct dependencies:\n\n- <a href="https://pydantic-docs.helpmanual.io/" target="_blank">pydantic</a>: makes\n  data validation and schema definition both handy and elegant.\n\n- <a href="https://motor.readthedocs.io/en/stable/" target="_blank">motor</a>: an\n  asyncio MongoDB driver officially developed by the MongoDB team.\n\n## Installation\n\n```shell\npip install odmantic\n```\n\n## Example\n\n> To enjoy an async context without any code boilerplate, you can reproduce the\n> following steps using the AsyncIO REPL (only for Python 3.8+).\n>\n> ```\n> python3.8 -m asyncio\n> ```\n>\n> If you are using an earlier version of Python you can use <a\n> href="https://ipython.readthedocs.io/en/stable/install/index.html"\n> target="_blank">IPython</a> which provide an Autoawait feature (starting from Python\n> 3.6).\n\n### Define your first model\n\n```python\nfrom typing import Optional\n\nfrom odmantic import Field, Model\n\n\nclass Publisher(Model):\n    name: str\n    founded: int = Field(ge=1440)\n    location: Optional[str] = None\n```\n\nBy defining the `Publisher` class, we\'ve just created an ODMantic model 🎉. In this\nexample, the model will represent book publishers.\n\nThis model contains three fields:\n\n- `name`: This is the name of the Publisher. This is a simple string field without any\n  specific validation but it will be required to build a new Publisher.\n\n- `founded`: This is the year of foundation of the Publisher. Since the printing press\n  has been invented in 1440, it would be handy to allow only values above 1440. The\n  `ge` keyword argument passed to the Field is exactly doing this. The model will\n  require a founded value greater or equal than 1440.\n\n- `location`: This field will contain the country code of the Publisher. Defining this\n  field as `Optional` with a `None` default value makes it a non required field that\n  will be set automatically when not specified.\n\nThe collection name has been defined by ODMantic as well. In this case it will be\n`publisher`.\n\n### Create some instances\n\n```python\ninstances = [\n    Publisher(name="HarperCollins", founded=1989, location="US"),\n    Publisher(name="Hachette Livre", founded=1826, location="FR"),\n    Publisher(name="Lulu", founded=2002)\n]\n```\n\nWe defined three instances of the Publisher model. They all have a `name` property as it\nwas required. All the foundations years are later than 1440. The last publisher has no\nlocation specified so by default this field is set to `None` (it will be stored as\n`null` in the database).\n\nFor now, those instances only exists locally. We will persist them in a database in the\nnext step.\n\n### Populate the database with your instances\n\n> For the next steps, you\'ll need to start a local MongoDB server.The easiest way is\n> to use docker. Simply run the next command in a terminal (closing the terminal will\n> terminate the MongoDB instance and remove the container).\n>\n> ```shell\n> docker run --rm --net=host mongo\n> ```\n\nFirst, let\'s connect to the database using the engine. In ODMantic, every database\noperation is performed using the engine object.\n\n```python\nfrom odmantic import AIOEngine\n\nengine = AIOEngine()\n```\n\nBy default, the `AIOEngine` (stands for AsyncIOEngine) automatically tries to connect to a\nMongoDB instance running locally (on port 27017). Since we didn\'t provide any database name, it will use\nthe database named `test` by default.\n\nThe next step is to persist the instances we created before. We can perform this\noperation using the `AIOEngine.save_all` method.\n\n```python\nawait engine.save_all(instances)\n```\n\nMost of the engine I/O methods are asynchronous, hence the `await` keyword used here.\nOnce the operation is complete, we should be able to see our created documents in the\ndatabase. You can use <a href="https://www.mongodb.com/products/compass"\ntarget="_blank">Compass</a> or <a href="https://robomongo.org/"\ntarget="_blank">RoboMongo</a> if you\'d like to have a graphical interface.\n\nAnother possibility is to use `mongo` CLI directly:\n\n```shell\nmongo --eval "db.publisher.find({})"\n```\n\nOutput:\n\n```json\nconnecting to: mongodb://127.0.0.1:27017\n{\n  "_id": ObjectId("5f67b331514d6855bc5c54c9"),\n  "founded": 1989,\n  "location": "US",\n  "name": "HarperCollins"\n},\n{\n  "_id": ObjectId("5f67b331514d6855bc5c54ca"),\n  "founded":1826,\n  "location": "FR",\n  "name": "Hachette Livre"\n},\n{\n  "_id": ObjectId("5f67b331514d6855bc5c54cb"),\n  "founded": 2002,\n  "location": null,\n  "name": "Lulu"\n}\n```\n\nThe created instances are stored in the `test` database under the `publisher` collection.\n\nWe can see that an `_id` field has been added to each document. MongoDB need this field\nto act as a primary key. Actually, this field is added by ODMantic and you can access it\nunder the name `id`.\n\n```python\nprint(instances[0].id)\n#> ObjectId("5f67b331514d6855bc5c54c9")\n```\n\n### Find instances matching a criteria\n\nSince we now have some documents in the database, we can start building some queries.\n\nFirst, let\'s find publishers created before the 2000s:\n\n```python\nearly_publishers = await engine.find(Publisher, Publisher.founded <= 2000)\nprint(early_publishers)\n#> [Publisher(name="HarperCollins", founded=1989, location="US),\n#>  Publisher(name="Hachette Livre", founded=1826, location="FR")]\n```\n\nHere, we called the `engine.find` method. The first argument we need to specify is the\nModel class we want to query on (in our case `Publisher`). The second argument is the\nactual query. Similarly to <a href="https://www.sqlalchemy.org/"\ntarget="_blank">SQLAlchemy</a>, you can build ODMantic queries using the regular python\noperators.\n\nWhen awaited, the `engine.find` method will return the list of matching instances stored\nin the database.\n\nAnother possibility is to query for at most one instance. For example, if we want to\nretrieve a publisher from Canada (CA):\n\n```python\nca_publisher = await engine.find_one(Publisher, Publisher.location == "CA")\nprint(ca_publisher)\n#> None\n```\n\nHere the result is `None` because no matching instances have been found in the database.\nThe `engine.find_one` method returns an instance if one exists in the database\notherwise, it will return `None`.\n\n### Modify an instance\n\nFinally, let\'s edit some instances. For example, we can set the `location` for the\npublisher named `Lulu`.\nFirst, we need to gather the instance from the database:\n\n```python\nlulu = await engine.find_one(Publisher, Publisher.name == "Lulu")\nprint(lulu)\n#> Publisher(name="Lulu", founded=2002, location=None)\n```\n\nWe still have the same instance, with no location set. We can change this field:\n\n```python\nlulu.location = "US"\nprint(lulu)\n#> Publisher(name="Lulu", founded=2002, location="US)\n```\n\nThe location has been changed locally but the last step to persist this change is to\nsave the document:\n\n```python\nawait engine.save(lulu)\n```\n\nWe can now check the database state:\n\n```shell\nmongo --eval "db.publisher.find({name: \'Lulu\'})"\n```\n\nOutput:\n\n```json hl_lines="5"\nconnecting to: mongodb://127.0.0.1:27017\n{\n  "_id": ObjectId("5f67b331514d6855bc5c54cb"),\n  "founded": 2002,\n  "location": "US",\n  "name": "Lulu"\n}\n```\n\nThe document have been successfully updated !\n\nNow, what if we would like to change the foundation date with an invalid one (before 1440) ?\n\n```python\nlulu.founded = 1000\n#> ValidationError: 1 validation error for Publisher\n#> founded\n#>   ensure this value is greater than 1440\n#>   (type=value_error.number.not_gt; limit_value=1440)\n```\n\nThis will raise an exception as it\'s not matching the model definition. The raised\nexception is actually a `ValidationError` created by from <a\nhref="https://pydantic-docs.helpmanual.io/usage/models/#error-handling"\ntarget="_blank">pydantic</a>.\n\n### Next steps\n\nIf you already have experience with Pydantic and FastAPI, the [Usage with FastAPI](https://art049.github.io/odmantic/usage_fastapi/) example might be interesting for you.\n\nOtherwise, to get started on more advanced practices like relations and building more\nadvanced queries, you can directly check the other sections of the\n[documentation](https://art049.github.io/odmantic/).\n\nIf you wish to contribute to the project (Thank you! :smiley:), you can have a look to the\n[Contributing](https://art049.github.io/odmantic/contributing/) section of the\ndocumentation.\n\n## License\n\nThis project is licensed under the terms of the <a\nhref="https://github.com/art049/odmantic/blob/master/LICENSE" target="_blank">ISC license</a>.\n',
    'author': 'Arthur Pastel',
    'author_email': 'arthur.pastel@gmail.com',
    'maintainer': None,
    'maintainer_email': None,
    'url': 'https://github.com/tangibleintelligence/odmantic',
    'packages': packages,
    'package_data': package_data,
    'install_requires': install_requires,
    'extras_require': extras_require,
    'python_requires': '>=3.6,<4.0',
}


setup(**setup_kwargs)
