From f44b7fa664beb6f7881e36d1d029a7e9906fdd25 Mon Sep 17 00:00:00 2001 From: Andrew Brookins Date: Fri, 29 Oct 2021 17:31:36 -0700 Subject: [PATCH] Work on docs, getting started guide --- README.md | 18 +- docs/connections.md | 0 docs/{embedded.md => embedded_models.md} | 0 docs/getting_started.md | 278 +++++++++++++++++++++++ docs/models_and_fields.md | 29 +++ docs/testing.md | 1 + docs/validation.md | 6 +- poetry.lock | 95 +++++++- pyproject.toml | 10 +- tox.ini | 9 + 10 files changed, 434 insertions(+), 12 deletions(-) create mode 100644 docs/connections.md rename docs/{embedded.md => embedded_models.md} (100%) create mode 100644 docs/models_and_fields.md create mode 100644 docs/testing.md create mode 100644 tox.ini diff --git a/README.md b/README.md index 40638a2..f1d6cd8 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ - [💻 Installation](#-installation) - [📚 Documentation](#-documentation) - [⛏️ Troubleshooting](#-troubleshooting) - - [✨ So how do you get RediSearch and RedisJSON?](#-so-how-do-you-get-redisearch-and-redisjson) + - [✨ So, How Do You Get RediSearch and RedisJSON?](#-so-how-do-you-get-redisearch-and-redisjson) - [❤️ Contributing](#-contributing) - [📝 License](#-license) @@ -111,7 +111,7 @@ Or, continue reading to see how Redis OM makes data validation a snap. ## ✓ Validating Data With Your Model -Redis OM uses [Pydantic](pydantic-url) to validate data based on the type annotations you assign to fields in a model class. +Redis OM uses [Pydantic][pydantic-url] to validate data based on the type annotations you assign to fields in a model class. This validation ensures that fields like `first_name`, which the `Customer` model marked as a `str`, are always strings. **But every Redis OM model is also a Pydantic model**, so you can use Pydantic validators like `EmailStr`, `Pattern`, and many more for complex validations! @@ -146,13 +146,15 @@ To learn more, see the [documentation on data validation](docs/validation.md). Data modeling, validation, and saving models to Redis all work regardless of how you run Redis. -Next, we'll show you the **rich query expressions** and **embedded models** Redis OM provides when the [RediSearch](redisearch-url) and [RedisJSON](redis-json-url) modules are installed in your Redis deployment, or you're using [Redis Enterprise](redis-enterprise-url). +Next, we'll show you the **rich query expressions** and **embedded models** Redis OM provides when the [RediSearch][redisearch-url] and [RedisJSON][redis-json-url] modules are installed in your Redis deployment, or you're using [Redis Enterprise][redis-enterprise-url]. **TIP**: *Wait, what's a Redis module?* If you aren't familiar with Redis modules, review the [So, How Do You Get RediSearch and RedisJSON?](#-so-how-do-you-get-redisearch-and-redisjson) section of this README. ### Querying -Let's make a small change to the `Customer` model we defined earlier to let Redis OM know that we want to query using the `last_name` and `age` fields: +Redis OM comes with a rich query language that allows you to query Redis with Python expressions. + +To show how this works, we'll make a small change to the `Customer` model we defined earlier. We'll add `Field(index=True)` to tell Redis OM that we want to index the `last_name` and `age` fields: ```python class Customer(HashModel): @@ -164,7 +166,7 @@ class Customer(HashModel): bio: Optional[str] ``` -Now, if we use this model with a Redis deployment that has the [RediSearch module](redisearch-url) installed, we can run queries like the following: +Now, if we use this model with a Redis deployment that has the [RediSearch module][redisearch-url] installed, we can run queries like the following: ```python # Find all customers with the last name "Brookins" @@ -184,7 +186,7 @@ These queries -- and more! -- are possible because **Redis OM manages indexes fo Querying with this index features a rich expression syntax inspired by the Django ORM, SQLAlchemy, and Peewee. We think you'll enjoy it! -To see more example queries, see the [documentation on querying](docs/querying.md). +To learn more about how to query with Redis OM, see the [documentation on querying](docs/querying.md). ### Embedded Models @@ -259,9 +261,9 @@ hit us up on the [Redis Discord Server](http://discord.gg/redis). ## ✨ So How Do You Get RediSearch and RedisJSON? -Some advanced features of Redis OM rely on core features from two source available Redis modules: [RediSearch](redisearch-url) and [RedisJSON](redis-json-url). +Some advanced features of Redis OM rely on core features from two source available Redis modules: [RediSearch][redisearch-url] and [RedisJSON][redis-json-url]. -You can run these modules in your self-hosted Redis deployment, or you can use [Redis Enterprise](redis-enterprise-url), which includes both modules. +You can run these modules in your self-hosted Redis deployment, or you can use [Redis Enterprise][redis-enterprise-url], which includes both modules. To learn more, read [our documentation](docs/redis_modules.md). diff --git a/docs/connections.md b/docs/connections.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/embedded.md b/docs/embedded_models.md similarity index 100% rename from docs/embedded.md rename to docs/embedded_models.md diff --git a/docs/getting_started.md b/docs/getting_started.md index e69de29..48f0e63 100644 --- a/docs/getting_started.md +++ b/docs/getting_started.md @@ -0,0 +1,278 @@ +# Getting Started With Redis OM + +## Introduction + +This tutorial will walk you through installing Redis OM, creating your first model, and using it to save and validate data. + +## Prerequisites + +Redis OM requires Python version 3.9 or above and a Redis instance to connect to. + +## Python + +Make sure you are running **Python version 3.9 or higher**: + +``` +python --version +Python 3.9.0 +``` + +If you don't have Python installed, you can download it from [Python.org](https://www.python.org/downloads/), use [Pyenv](https://github.com/pyenv/pyenv), or install Python with your operating system's package manager. + +## Redis + +Redis OM saves data in Redis, so you will need Redis installed and running to complete this tutorial. + +### Downloading Redis + +The latest version of Redis is available from [Redis.io](https://redis.io/). You can also install Redis with your operating system's package manager. + +**NOTE:** This tutorial will guide you through starting Redis locally, but the instructions will also work if Redis is running on a remote server. + +### Installing Redis On Windows + +Redis doesn't run directly on Windows, but you can use Windows Subsystem for Linux (WSL) to run Redis. See [our video on YouTube](https://youtu.be/_nFwPTHOMIY) for a walk-through. + +Windows users can also use Docker. See the next section on running Redis with Docker for more information. + +### Running Redis With Docker + +Instead of installing Redis manually or with a package manager, you can run Redis with Docker. The official Redis Docker image is hosted on [Docker Hub](https://hub.docker.com/_/redis). + +**TIP:** If you plan on using Docker, we recommend the [redismod](https://hub.docker.com/r/redislabs/redismod) image because it includes the RediSearch and RedisJSON modules. + +## Recommended: RediSearch and RedisJSON + +Redis OM relies on the [RediSearch][redisearch-url] and [RedisJSON][redis-json-url] Redis modules to support [rich queries](querying.md) and [embedded models](embedded_models.md). + +You don't need these Redis modules to use Redis OM's data modeling, validation, and persistence features, but we recommend them to get the most out of Redis OM. + +The easiest way to run these Redis modules during local development is to use the [redismod](https://hub.docker.com/r/redislabs/redismod) Docker image. + +You can quickly start Redis with the redismod Docker image by running the following command: + + docker run -d -p 6379:6379 redislabs/redismod + +**TIP:** The `-d` option runs Redis in the background. + +For other installation methods, follow the "Quick Start" guides on both modules' home pages for alternative installation methods. + +## Start Redis + +Before you get started with Redis OM, make sure you start Redis. + +The command you use to start Redis will depend on how you installed it. + +### Ubuntu Linux (Including WSL) + +If you installed Redis using `apt`, start it with the `systemctl` command: + + sudo systemctl restart redis.service + +Otherwise, you can start the server manually: + + redis-server start + +### macOS with Homebrew + + brew services start redis + +### Docker + +The command to start Redis with Docker depends on the image you've chosen to use. + +#### Docker with the redismod image (recommended) + + docker run -d -p 6379:6379 redislabs/redismod + +### Docker iwth the redis image + + docker run -d -p 6379:6379 redis + +## Installing Redis OM + +You can install Redis OM with `pip` by running the following command: + + pip install redis-om + +Or, if you're using Poetry, you can install Redis OM with the following command: + + poetry install redis-om + +With Pipenv, the command is: + + pipenv install redis-om + +## Setting the Redis URL Environment Variable + +We're almost ready to create a Redis OM model! But first, we need to make sure that Redis OM knows how to connect to Redis. + +By default, Redis OM tries to connect to Redis on your localhost at port 6379. Most local install methods will result in Redis running at this location, in which case you don't need to do anything special. + +However, if you configured Redis to run on a different port, or if you're using a remote Redis server, you'll need to set the `REDIS_URL` environment variable. + +The `REDIS_URL` environment variable follows the redis-py URL format: + + redis://[[username]:[password]]@localhost:6379/[database number] + +The default connection is eqivalent to the following `REDIS_URL` environment variable: + + redis://@localhost:6379 + +**TIP:** Redis databases are numbered, and the default is 0. You can leave off the database number to use the default database. + +Other supported prefixes include "rediss" for SSL connections and "unix" for Unix domain sockets: + + rediss://[[username]:[password]]@localhost:6379/0 + unix://[[username]:[password]]@/path/to/socket.sock?db=0 + +For more details about how to connect to Redis with Redis OM, see the [connections documentation](connections.md). + +### Redis Cluster Support + +Redis OM supports connecting to Redis Cluster, but this preview release does not support doing so with the `REDIS_URL` environment variable. However, you can connect by manually creating a connection object. + +See the [connections documentation](connections.md) for examples of connecting to Redis Cluster. + +Support for connecting to Redis Cluster via `REDIS_URL` will be added in a future release. + +## Defining a Model + +In this tutorial, we'll create a `Customer` model that validates and saves data. Let's start with a basic definition of the model. We'll add features as we go along. + +```python +import datetime +from typing import Optional + +from redis_om.model import ( + HashModel, +) + + +class Customer(HashModel): + first_name: str + last_name: str + email: str + join_date: datetime.date + age: int + bio: str +``` + +There are a few details to note: + +1. Our `Customer` model extends the `HashModel` class. This means that it will be saved to Redis as a hash. The other model class that Redis OM provides is `JsonModel`, which we'll discuss later. +2. We've specified the model's fields using Python type annotations. + +Let's dig into these two details a bit more. + +### The HashModel Class + +When you subclass `HashModel`, your subclass is both a Redis OM model, with methods for saving data to Redis, *and* a Pydantic model. + +This means that you can use Pydantic field validations with your Redis OM models, which we'll cover later, when we talk about validation. But this also means you can use Redis OM models anywhere you would use a Pydantic model, like in your FastAPI applications. 🤯 + +### Type Annotations + +The type annotations you add to your model fields are used for a few purposes: + +* Validating data with Pydantic validators +* Serializing data Redis +* Deserializing data from Redis + +We'll see examples of these throughout the course of this tutorial. + +An important detail about the `HashModel` class is that it does not support `list`, `set`, or mapping (like `dict`) types. This is because Redis hashes cannot contain lists, sets, or other hashes. + +If you want to model fields with a list, set, or mapping type, or another model, you'll need to use the `JsonModel` class, which can support these types, as well as embedded models. + +## Creating Models + +Let's see what creating a model object looks like: + +```python +andrew = Customer( + first_name="Andrew", + last_name="Brookins", + email="andrew.brookins@example.com", + join_date=datetime.date.today(), + age=38, + bio="Python developer, works at Redis, Inc." +) +``` + +### Optional Fields + +What would happen if we left out one of these fields, like `bio`? + +```python +Customer( + first_name="Andrew", + last_name="Brookins", + email="andrew.brookins@example.com", + join_date=datetime.date.today(), + age=38) +``` + +All fields are required because none of the fields are marked `Optional`, so we get a validation error: + +``` +ValidationError: 1 validation error for Customer +bio + field required (type=value_error.missing) +``` + +If we want the `bio` field to be optional, we need to change the type annotation: + +```python +class Customer(HashModel): + first_name: str + last_name: str + email: str + join_date: datetime.date + age: int + bio: Optional[str] +``` + +Now we can create `Customer` objects with or without the `bio` field. + +### Default Values + +Fields can have default values. + +```python +class Customer(HashModel): + first_name: str + last_name: str + email: str + join_date: datetime.date + age: int + bio: Optional[str] = "Super dope" +``` + +Now, if we create a `Customer` object without a `bio` field, it will use the default value. + +```python +andrew = Customer( + first_name="Andrew", + last_name="Brookins", + email="andrew.brookins@example.com", + join_date=datetime.date.today(), + age=38) + +print(andrew.bio) +'Super Dope' +``` + +## Saving Models + +## Examining Your Data In Redis + +## Validating Data + +## Next Steps + +Now that you know the basics of working with Redis OM, continue on for all the nitty-gritty details about [models and fields](validation.md). + + +[redisearch-url]: https://oss.redis.com/redisearch/ +[redis-json-url]: https://oss.redis.com/redisjson/ diff --git a/docs/models_and_fields.md b/docs/models_and_fields.md new file mode 100644 index 0000000..b25d4d3 --- /dev/null +++ b/docs/models_and_fields.md @@ -0,0 +1,29 @@ +# Models and Fields + +## Introduction + +## Saving Data As Hashes With HashModel + +### What Does Redis Store? + +## Saving Data With JSON With JsonModel + +### What Does Redis Store? + +## Primary Keys + +### Why Primary Keys Matter to Redis OM + +### Using the Default Primary Key + +### Using a Custom Primary Key + +## Meta Classes + +## Subclassing Models + +### Subclassing and Meta Objects + +## Saving Models + + diff --git a/docs/testing.md b/docs/testing.md new file mode 100644 index 0000000..0f1c1c5 --- /dev/null +++ b/docs/testing.md @@ -0,0 +1 @@ +# Testing Your Models diff --git a/docs/validation.md b/docs/validation.md index 5b59a94..9b165dd 100644 --- a/docs/validation.md +++ b/docs/validation.md @@ -1,6 +1,6 @@ # Validation -Redis OM uses [Pydantic](pydantic-url) behind the scenes to validate data at runtime, based on the model's type annotations. +Redis OM uses [Pydantic][pydantic-url] behind the scenes to validate data at runtime, based on the model's type annotations. ## Basic Type Validation @@ -68,4 +68,6 @@ Once again, we get the valiation error: pydantic.error_wrappers.ValidationError: 1 validation error for Customer email value is not a valid email address (type=value_error.email) -``` \ No newline at end of file +``` + +[pydantic-url]: https://github.com/samuelcolvin/pydantic diff --git a/poetry.lock b/poetry.lock index 0ef59fd..b6eada7 100644 --- a/poetry.lock +++ b/poetry.lock @@ -72,6 +72,18 @@ category = "dev" optional = false python-versions = "*" +[[package]] +name = "backports.entry-points-selectable" +version = "1.1.0" +description = "Compatibility shim providing selectable entry points for older implementations" +category = "dev" +optional = false +python-versions = ">=2.7" + +[package.extras] +docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] +testing = ["pytest (>=4.6)", "pytest-flake8", "pytest-cov", "pytest-black (>=0.3.7)", "pytest-mypy", "pytest-checkdocs (>=2.4)", "pytest-enabler (>=1.0.1)"] + [[package]] name = "bandit" version = "1.7.0" @@ -217,6 +229,14 @@ category = "dev" optional = false python-versions = ">=3.5" +[[package]] +name = "distlib" +version = "0.3.3" +description = "Distribution utilities" +category = "dev" +optional = false +python-versions = "*" + [[package]] name = "dnspython" version = "2.1.0" @@ -263,6 +283,18 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [package.extras] testing = ["pre-commit"] +[[package]] +name = "filelock" +version = "3.3.1" +description = "A platform independent file lock." +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.extras] +docs = ["furo (>=2021.8.17b43)", "sphinx (>=4.1)", "sphinx-autodoc-typehints (>=1.12)"] +testing = ["covdefaults (>=1.2.0)", "coverage (>=4)", "pytest (>=4)", "pytest-cov", "pytest-timeout (>=1.4.2)"] + [[package]] name = "flake8" version = "4.0.1" @@ -918,6 +950,28 @@ category = "dev" optional = false python-versions = ">=3.6" +[[package]] +name = "tox" +version = "3.24.4" +description = "tox is a generic virtualenv management and test command line tool" +category = "dev" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" + +[package.dependencies] +colorama = {version = ">=0.4.1", markers = "platform_system == \"Windows\""} +filelock = ">=3.0.0" +packaging = ">=14" +pluggy = ">=0.12.0" +py = ">=1.4.17" +six = ">=1.14.0" +toml = ">=0.9.4" +virtualenv = ">=16.0.0,<20.0.0 || >20.0.0,<20.0.1 || >20.0.1,<20.0.2 || >20.0.2,<20.0.3 || >20.0.3,<20.0.4 || >20.0.4,<20.0.5 || >20.0.5,<20.0.6 || >20.0.6,<20.0.7 || >20.0.7" + +[package.extras] +docs = ["pygments-github-lexers (>=0.0.5)", "sphinx (>=2.0.0)", "sphinxcontrib-autoprogram (>=0.1.5)", "towncrier (>=18.5.0)"] +testing = ["flaky (>=3.4.0)", "freezegun (>=0.3.11)", "psutil (>=5.6.1)", "pytest (>=4.0.0)", "pytest-cov (>=2.5.1)", "pytest-mock (>=1.10.0)", "pytest-randomly (>=1.0.0)", "pytest-xdist (>=1.22.2)", "pathlib2 (>=2.3.3)"] + [[package]] name = "tqdm" version = "4.62.3" @@ -1001,6 +1055,25 @@ brotli = ["brotlipy (>=0.6.0)"] secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] +[[package]] +name = "virtualenv" +version = "20.9.0" +description = "Virtual Python Environment builder" +category = "dev" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" + +[package.dependencies] +"backports.entry-points-selectable" = ">=1.0.4" +distlib = ">=0.3.1,<1" +filelock = ">=3.2,<4" +platformdirs = ">=2,<3" +six = ">=1.9.0,<2" + +[package.extras] +docs = ["proselint (>=0.10.2)", "sphinx (>=3)", "sphinx-argparse (>=0.2.5)", "sphinx-rtd-theme (>=0.4.3)", "towncrier (>=19.9.0rc1)"] +testing = ["coverage (>=4)", "coverage-enable-subprocess (>=1)", "flaky (>=3)", "pytest (>=4)", "pytest-env (>=0.6.2)", "pytest-freezegun (>=0.4.1)", "pytest-mock (>=2)", "pytest-randomly (>=1)", "pytest-timeout (>=1)", "packaging (>=20.0)"] + [[package]] name = "wcwidth" version = "0.2.5" @@ -1040,7 +1113,7 @@ testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytes [metadata] lock-version = "1.1" python-versions = "^3.8" -content-hash = "de30b2382aaeb2fe0675658bce5a3e5bc21a14e85c66d94a90054bc73a7831cd" +content-hash = "6ee2fea3f5714de8992d03450cbe4a6ce7ac41825252877777a6d61b777d4934" [metadata.files] aioredis = [ @@ -1071,6 +1144,10 @@ backcall = [ {file = "backcall-0.2.0-py2.py3-none-any.whl", hash = "sha256:fbbce6a29f263178a1f7915c1940bde0ec2b2a967566fe1c65c1dfb7422bd255"}, {file = "backcall-0.2.0.tar.gz", hash = "sha256:5cbdbf27be5e7cfadb448baf0aa95508f91f2bbc6c6437cd9cd06e2a4c215e1e"}, ] +"backports.entry-points-selectable" = [ + {file = "backports.entry_points_selectable-1.1.0-py2.py3-none-any.whl", hash = "sha256:a6d9a871cde5e15b4c4a53e3d43ba890cc6861ec1332c9c2428c92f977192acc"}, + {file = "backports.entry_points_selectable-1.1.0.tar.gz", hash = "sha256:988468260ec1c196dab6ae1149260e2f5472c9110334e5d51adcb77867361f6a"}, +] bandit = [ {file = "bandit-1.7.0-py3-none-any.whl", hash = "sha256:216be4d044209fa06cf2a3e51b319769a51be8318140659719aa7a115c35ed07"}, {file = "bandit-1.7.0.tar.gz", hash = "sha256:8a4c7415254d75df8ff3c3b15cfe9042ecee628a1e40b44c15a98890fbfc2608"}, @@ -1212,6 +1289,10 @@ decorator = [ {file = "decorator-5.1.0-py3-none-any.whl", hash = "sha256:7b12e7c3c6ab203a29e157335e9122cb03de9ab7264b137594103fd4a683b374"}, {file = "decorator-5.1.0.tar.gz", hash = "sha256:e59913af105b9860aa2c8d3272d9de5a56a4e608db9a2f167a8480b323d529a7"}, ] +distlib = [ + {file = "distlib-0.3.3-py2.py3-none-any.whl", hash = "sha256:c8b54e8454e5bf6237cc84c20e8264c3e991e824ef27e8f1e81049867d861e31"}, + {file = "distlib-0.3.3.zip", hash = "sha256:d982d0751ff6eaaab5e2ec8e691d949ee80eddf01a62eaa96ddb11531fe16b05"}, +] dnspython = [ {file = "dnspython-2.1.0-py3-none-any.whl", hash = "sha256:95d12f6ef0317118d2a1a6fc49aac65ffec7eb8087474158f42f26a639135216"}, {file = "dnspython-2.1.0.zip", hash = "sha256:e4a87f0b573201a0f3727fa18a516b055fd1107e0e5477cded4a2de497df1dd4"}, @@ -1228,6 +1309,10 @@ execnet = [ {file = "execnet-1.9.0-py2.py3-none-any.whl", hash = "sha256:a295f7cc774947aac58dde7fdc85f4aa00c42adf5d8f5468fc630c1acf30a142"}, {file = "execnet-1.9.0.tar.gz", hash = "sha256:8f694f3ba9cc92cab508b152dcfe322153975c29bda272e2fd7f3f00f36e47c5"}, ] +filelock = [ + {file = "filelock-3.3.1-py3-none-any.whl", hash = "sha256:2b5eb3589e7fdda14599e7eb1a50e09b4cc14f34ed98b8ba56d33bfaafcbef2f"}, + {file = "filelock-3.3.1.tar.gz", hash = "sha256:34a9f35f95c441e7b38209775d6e0337f9a3759f3565f6c5798f19618527c76f"}, +] flake8 = [ {file = "flake8-4.0.1-py2.py3-none-any.whl", hash = "sha256:479b1304f72536a55948cb40a32dce8bb0ffe3501e26eaf292c7e60eb5e0428d"}, {file = "flake8-4.0.1.tar.gz", hash = "sha256:806e034dda44114815e23c16ef92f95c91e4c71100ff52813adf7132a6ad870d"}, @@ -1591,6 +1676,10 @@ tomli = [ {file = "tomli-1.2.1-py3-none-any.whl", hash = "sha256:8dd0e9524d6f386271a36b41dbf6c57d8e32fd96fd22b6584679dc569d20899f"}, {file = "tomli-1.2.1.tar.gz", hash = "sha256:a5b75cb6f3968abb47af1b40c1819dc519ea82bcc065776a866e8d74c5ca9442"}, ] +tox = [ + {file = "tox-3.24.4-py2.py3-none-any.whl", hash = "sha256:5e274227a53dc9ef856767c21867377ba395992549f02ce55eb549f9fb9a8d10"}, + {file = "tox-3.24.4.tar.gz", hash = "sha256:c30b57fa2477f1fb7c36aa1d83292d5c2336cd0018119e1b1c17340e2c2708ca"}, +] tqdm = [ {file = "tqdm-4.62.3-py2.py3-none-any.whl", hash = "sha256:8dd278a422499cd6b727e6ae4061c40b48fce8b76d1ccbf5d34fca9b7f925b0c"}, {file = "tqdm-4.62.3.tar.gz", hash = "sha256:d359de7217506c9851b7869f3708d8ee53ed70a1b8edbba4dbcb47442592920d"}, @@ -1620,6 +1709,10 @@ urllib3 = [ {file = "urllib3-1.26.7-py2.py3-none-any.whl", hash = "sha256:c4fdf4019605b6e5423637e01bc9fe4daef873709a7973e195ceba0a62bbc844"}, {file = "urllib3-1.26.7.tar.gz", hash = "sha256:4987c65554f7a2dbf30c18fd48778ef124af6fab771a377103da0585e2336ece"}, ] +virtualenv = [ + {file = "virtualenv-20.9.0-py2.py3-none-any.whl", hash = "sha256:1d145deec2da86b29026be49c775cc5a9aab434f85f7efef98307fb3965165de"}, + {file = "virtualenv-20.9.0.tar.gz", hash = "sha256:bb55ace18de14593947354e5e6cd1be75fb32c3329651da62e92bf5d0aab7213"}, +] wcwidth = [ {file = "wcwidth-0.2.5-py2.py3-none-any.whl", hash = "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784"}, {file = "wcwidth-0.2.5.tar.gz", hash = "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83"}, diff --git a/pyproject.toml b/pyproject.toml index 8859537..1335879 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,11 +3,18 @@ name = "redis-om" version = "0.0.1" description = "A high-level library containing useful Redis abstractions and tools, like an ORM and leaderboard." authors = ["Andrew Brookins "] +maintainers = ["Andrew Brookins "] license = "BSD-3-Clause" readme = "README.md" +repository = "https://github.com/redis-developer/redis-om-python" +classifiers = [ + "Development Status :: 3 - Alpha", + "Intended Audience :: Developers", + "Topic :: Database :: Front-Ends" +] [tool.poetry.dependencies] -python = "^3.8" +python = "^3.9" redis = "^3.5.3" aioredis = "^2.0.0" pydantic = "^1.8.2" @@ -33,6 +40,7 @@ pytest-cov = "^3.0.0" pytest-xdist = "^2.4.0" twine = "^3.4.2" email-validator = "^1.1.3" +tox = "^3.24.4" [tool.poetry.scripts] migrate = "redis_om.model.cli.migrate:migrate" diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..6417a44 --- /dev/null +++ b/tox.ini @@ -0,0 +1,9 @@ +[tox] +skipsdist = true +envlist = py37, py38, py39, py310 + +[testenv] +whitelist_externals = poetry +commands = + poetry install -v + poetry run pytest \ No newline at end of file