diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index a969b226..74b2a4df 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -32,7 +32,7 @@ jobs: python -m pip install -U pip poetry poetry --version poetry config --local virtualenvs.in-project true - poetry install + poetry install --extras "pydantic faust" - name: Test run: ./scripts/test diff --git a/README.md b/README.md index f2590e67..b0753990 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,6 @@ Generate [Avro](https://avro.apache.org/docs/1.8.2/spec.html) Schemas from a Python class [![Tests](https://github.com/marcosschroh/dataclasses-avroschema/actions/workflows/tests.yaml/badge.svg)](https://github.com/marcosschroh/dataclasses-avroschema/actions/workflows/tests.yaml) -[![Build Status](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Factions-badge.atrox.dev%2Fmarcosschroh%2Fdataclasses-avroschema%2Fbadge%3Fref%3Dmaster&style=flat)](https://actions-badge.atrox.dev/marcosschroh/dataclasses-avroschema/goto?ref=master) [![GitHub license](https://img.shields.io/github/license/marcosschroh/dataclasses-avroschema.svg)](https://github.com/marcosschroh/dataclasses-avroschema/blob/master/LICENSE) [![codecov](https://codecov.io/gh/marcosschroh/dataclasses-avroschema/branch/master/graph/badge.svg)](https://codecov.io/gh/marcosschroh/dataclasses-avroschema) ![python version](https://img.shields.io/badge/python-3.7%2B-yellowgreen) @@ -14,21 +13,22 @@ Generate [Avro](https://avro.apache.org/docs/1.8.2/spec.html) Schemas from a Pyt ## Installation -```bash -pip install dataclasses-avroschema -``` +with `pip` or `poetry`: -or with `pydantic` funcionalities +`pip install dataclasses-avroschema` or `poetry install` -```bash -pip install 'dataclasses-avroschema[pydantic]' -``` +### Extras -or with command line [dc-avro](https://marcosschroh.github.io/dc-avro/) +[pydantic](https://docs.pydantic.dev/): `pip install 'dataclasses-avroschema[pydantic]'` or `poetry install --extras "pydantic"` +[faust-streaming](https://github.com/faust-streaming/faust): `pip install 'dataclasses-avroschema[faust]'` or `poetry install --extras "faust"` -```bash -pip install 'dataclasses-avroschema[cli]' -``` +*Note*: You can install all extra dependencies with `pip install dataclasses-avroschema ".[extras]"` or `poetry install --extras "pydantic faust"` + +### CLI + +To add `avro schemas cli` install [dc-avro](https://marcosschroh.github.io/dc-avro/) + +`pip install 'dataclasses-avroschema[cli]'` or `poetry install --with cli` ## Documentation @@ -262,6 +262,24 @@ UserAdvance.avro_schema() ] }' +# Json schema +UserAdvance.json_schema() + +{ + "title": "UserAdvance", + "description": "UserAdvance(*, name: str, age: int, pets: List[str] = None, ...", + "type": "object", + "properties": { + "name": {"title": "Name", "type": "string"}, + "age": {"title": "Age", "type": "integer"}, + "pets": {"title": "Pets", "type": "array", "items": {"type": "string"}}, + "accounts": {"title": "Accounts", "type": "object", "additionalProperties": {"type": "integer"}}, + "has_car": {"title": "Has Car", "default": false, "type": "boolean"}, + "favorite_colors": {"default": "BLUE", "allOf": [{"$ref": "#/definitions/FavoriteColor"}]}, + "country": {"title": "Country", "default": "Argentina", "type": "string"}, + "address": {"title": "Address", "type": "string"}}, "required": ["name", "age"], "definitions": {"FavoriteColor": {"title": "FavoriteColor", "description": "An enumeration.", "enum": ["BLUE", "YELLOW", "GREEN"], "type": "string"}} +} + user = UserAdvance(name="bond", age=50) # pydantic diff --git a/dataclasses_avroschema/fields.py b/dataclasses_avroschema/fields.py index 0f62b33d..8e852db8 100644 --- a/dataclasses_avroschema/fields.py +++ b/dataclasses_avroschema/fields.py @@ -13,8 +13,8 @@ import uuid from collections import OrderedDict -import inflect from faker import Faker +from inflector import Inflector from pytz import utc from typing_extensions import get_args, get_origin @@ -32,7 +32,7 @@ logger = logging.getLogger(__name__) fake = Faker() -p = inflect.engine() +p = Inflector() @dataclasses.dataclass # type: ignore @@ -66,13 +66,7 @@ def _get_self_reference_type(a_type: typing.Any) -> str: @staticmethod def get_singular_name(name: str) -> str: - singular = p.singular_noun(name) - - # do the check because of mypy. - # p.singular_noun returns Union[str, bool] - if isinstance(singular, str): - return singular - return name + return p.singularize(name) def get_metadata(self) -> typing.List[typing.Tuple[str, str]]: meta_data_for_template = [] diff --git a/docs/index.md b/docs/index.md index 2ba90282..3f8722d7 100644 --- a/docs/index.md +++ b/docs/index.md @@ -13,21 +13,22 @@ Generate [Avro](https://avro.apache.org/docs/1.8.2/spec.html) Schemas from a Pyt ## Installation -```bash -pip install dataclasses-avroschema -``` +with `pip` or `poetry`: -or with `pydantic` funcionalities +`pip install dataclasses-avroschema` or `poetry install` -```bash -pip install 'dataclasses-avroschema[pydantic]' -``` +### Extras -or with command line [dc-avro](https://marcosschroh.github.io/dc-avro/) +[pydantic](https://docs.pydantic.dev/): `pip install 'dataclasses-avroschema[pydantic]'` or `poetry install --extras "pydantic"` +[faust-streaming](https://github.com/faust-streaming/faust): `pip install 'dataclasses-avroschema[faust]'` or `poetry install --extras "faust"` -```bash -pip install 'dataclasses-avroschema[cli]' -``` +*Note*: You can install all extra dependencies with `pip install dataclasses-avroschema ".[extras]"` or `poetry install --extras "pydantic faust"` + +### CLI + +To add `avro schemas cli` install [dc-avro](https://marcosschroh.github.io/dc-avro/) + +`pip install 'dataclasses-avroschema[cli]'` or `poetry install --with cli` ## Usage diff --git a/poetry.lock b/poetry.lock index e06bf015..7b2bee35 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2,7 +2,7 @@ name = "aiofiles" version = "22.1.0" description = "File support for asyncio." -category = "main" +category = "dev" optional = true python-versions = ">=3.7,<4.0" @@ -11,7 +11,7 @@ name = "aiohttp" version = "3.8.4" description = "Async http client/server framework (asyncio)" category = "main" -optional = false +optional = true python-versions = ">=3.6" [package.dependencies] @@ -33,7 +33,7 @@ name = "aiohttp-cors" version = "0.7.0" description = "CORS support for aiohttp" category = "main" -optional = false +optional = true python-versions = "*" [package.dependencies] @@ -44,7 +44,7 @@ name = "aiokafka" version = "0.8.0" description = "Kafka integration with asyncio." category = "main" -optional = false +optional = true python-versions = ">=3.7" [package.dependencies] @@ -64,7 +64,7 @@ name = "aiosignal" version = "1.3.1" description = "aiosignal: a list of registered asynchronous callbacks" category = "main" -optional = false +optional = true python-versions = ">=3.7" [package.dependencies] @@ -74,7 +74,7 @@ frozenlist = ">=1.1.0" name = "anyio" version = "3.6.2" description = "High level compatibility layer for multiple asynchronous event loop implementations" -category = "main" +category = "dev" optional = true python-versions = ">=3.6.2" @@ -108,7 +108,7 @@ name = "async-timeout" version = "4.0.2" description = "Timeout context manager for asyncio programs" category = "main" -optional = false +optional = true python-versions = ">=3.6" [package.dependencies] @@ -119,7 +119,7 @@ name = "asynctest" version = "0.13.0" description = "Enhance the standard unittest package with features for testing asyncio libraries" category = "main" -optional = false +optional = true python-versions = ">=3.5" [[package]] @@ -127,7 +127,7 @@ name = "attrs" version = "23.1.0" description = "Classes Without Boilerplate" category = "main" -optional = false +optional = true python-versions = ">=3.7" [package.dependencies] @@ -168,7 +168,7 @@ uvloop = ["uvloop (>=0.15.2)"] name = "certifi" version = "2022.12.7" description = "Python package for providing Mozilla's CA Bundle." -category = "main" +category = "dev" optional = false python-versions = ">=3.6" @@ -208,7 +208,7 @@ name = "colorlog" version = "6.7.0" description = "Add colours to the output of Python's logging module." category = "main" -optional = false +optional = true python-versions = ">=3.6" [package.dependencies] @@ -242,7 +242,7 @@ typing-extensions = ">=4.0.1,<5.0.0" name = "commonmark" version = "0.9.1" description = "Python parser for the CommonMark Markdown spec" -category = "main" +category = "dev" optional = true python-versions = "*" @@ -268,7 +268,7 @@ name = "croniter" version = "1.3.14" description = "croniter provides iteration for datetime object with cron like format" category = "main" -optional = false +optional = true python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [package.dependencies] @@ -289,7 +289,7 @@ dev = ["black", "coveralls", "mypy", "pre-commit", "pylint", "pytest (>=5)", "py name = "dc-avro" version = "0.6.4" description = "" -category = "main" +category = "dev" optional = true python-versions = ">=3.7,<4.0" @@ -312,7 +312,7 @@ python-versions = ">=3.6" name = "deepdiff" version = "6.3.0" description = "Deep Difference and Search of any Python object/data. Recreate objects by adding adding deltas to each other." -category = "main" +category = "dev" optional = true python-versions = ">=3.7" @@ -365,7 +365,7 @@ name = "faust-streaming" version = "0.10.11" description = "Python Stream processing." category = "main" -optional = false +optional = true python-versions = ">=3.7.0" [package.dependencies] @@ -409,7 +409,7 @@ name = "frozenlist" version = "1.3.3" description = "A list-like structure which implements collections.abc.MutableSequence" category = "main" -optional = false +optional = true python-versions = ">=3.7" [[package]] @@ -430,7 +430,7 @@ dev = ["flake8", "markdown", "twine", "wheel"] name = "h11" version = "0.14.0" description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" -category = "main" +category = "dev" optional = true python-versions = ">=3.7" @@ -441,7 +441,7 @@ typing-extensions = {version = "*", markers = "python_version < \"3.8\""} name = "httpcore" version = "0.16.3" description = "A minimal low-level HTTP client." -category = "main" +category = "dev" optional = true python-versions = ">=3.7" @@ -459,7 +459,7 @@ socks = ["socksio (>=1.0.0,<2.0.0)"] name = "httpx" version = "0.23.3" description = "The next generation HTTP client." -category = "main" +category = "dev" optional = true python-versions = ">=3.7" @@ -501,19 +501,12 @@ perf = ["ipython"] testing = ["flake8 (<5)", "flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)"] [[package]] -name = "inflect" -version = "6.0.4" -description = "Correctly generate plurals, singular nouns, ordinals, indefinite articles; convert numbers to words" +name = "inflector" +version = "3.1.0" +description = "Inflector for Python" category = "main" optional = false -python-versions = ">=3.7" - -[package.dependencies] -pydantic = ">=1.9.1" - -[package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["flake8 (<5)", "pygments", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] +python-versions = "*" [[package]] name = "iniconfig" @@ -528,7 +521,7 @@ name = "intervaltree" version = "3.1.0" description = "Editable interval tree data structure for Python 2 and 3" category = "main" -optional = false +optional = true python-versions = "*" [package.dependencies] @@ -553,7 +546,7 @@ name = "kafka-python" version = "2.0.2" description = "Pure Python client for Apache Kafka" category = "main" -optional = false +optional = true python-versions = "*" [package.extras] @@ -647,7 +640,7 @@ name = "mode-streaming" version = "0.3.5" description = "AsyncIO Service-based programming." category = "main" -optional = false +optional = true python-versions = ">=3.7" [package.dependencies] @@ -667,7 +660,7 @@ name = "multidict" version = "6.0.4" description = "multidict implementation" category = "main" -optional = false +optional = true python-versions = ">=3.7" [[package]] @@ -703,7 +696,7 @@ name = "opentracing" version = "2.4.0" description = "OpenTracing API for Python. See documentation at http://opentracing.io" category = "main" -optional = false +optional = true python-versions = "*" [package.extras] @@ -713,7 +706,7 @@ tests = ["Sphinx", "doubles", "flake8", "flake8-quotes", "gevent", "mock", "pyte name = "ordered-set" version = "4.1.0" description = "An OrderedSet is a custom MutableSet that remembers its order, so that every" -category = "main" +category = "dev" optional = true python-versions = ">=3.7" @@ -782,7 +775,7 @@ name = "pydantic" version = "1.10.7" description = "Data validation and settings management using python type hints" category = "main" -optional = false +optional = true python-versions = ">=3.7" [package.dependencies] @@ -796,7 +789,7 @@ email = ["email-validator (>=1.0.3)"] name = "pygments" version = "2.15.1" description = "Pygments is a syntax highlighting package written in Python." -category = "main" +category = "dev" optional = false python-versions = ">=3.7" @@ -932,7 +925,7 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] name = "rfc3986" version = "1.5.0" description = "Validating URI References per RFC 3986" -category = "main" +category = "dev" optional = true python-versions = "*" @@ -946,7 +939,7 @@ idna2008 = ["idna"] name = "rich" version = "12.6.0" description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" -category = "main" +category = "dev" optional = true python-versions = ">=3.6.3,<4.0.0" @@ -970,7 +963,7 @@ python-versions = ">=3.7" name = "shellingham" version = "1.5.0.post1" description = "Tool to Detect Surrounding Shell" -category = "main" +category = "dev" optional = true python-versions = ">=3.7" @@ -986,7 +979,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" name = "sniffio" version = "1.3.0" description = "Sniff out which async library your code is running under" -category = "main" +category = "dev" optional = true python-versions = ">=3.7" @@ -995,7 +988,7 @@ name = "sortedcontainers" version = "2.4.0" description = "Sorted Containers -- Sorted List, Sorted Dict, Sorted Set" category = "main" -optional = false +optional = true python-versions = "*" [[package]] @@ -1022,7 +1015,7 @@ name = "terminaltables" version = "3.1.10" description = "Generate simple tables in terminals from a nested list of strings." category = "main" -optional = false +optional = true python-versions = ">=2.6" [[package]] @@ -1053,7 +1046,7 @@ python-versions = ">=3.6" name = "typer" version = "0.7.0" description = "Typer, build great CLIs. Easy to code. Based on Python type hints." -category = "main" +category = "dev" optional = true python-versions = ">=3.6" @@ -1103,7 +1096,7 @@ name = "venusian" version = "3.0.0" description = "A library for deferring decorator actions" category = "main" -optional = false +optional = true python-versions = ">=3.5" [package.extras] @@ -1134,7 +1127,7 @@ name = "yarl" version = "1.8.2" description = "Yet another URL library" category = "main" -optional = false +optional = true python-versions = ">=3.7" [package.dependencies] @@ -1155,13 +1148,13 @@ docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] [extras] -cli = ["dc-avro"] +faust = ["faust-streaming"] pydantic = ["pydantic"] [metadata] lock-version = "1.1" python-versions = "^3.7" -content-hash = "00fd9176808b031e9c4db030cc7cde39bba3c48e9f458ea08fc08ba825b53009" +content-hash = "12cfb313b4ffaae5ac1b2fd46a5de3f40505f7267fbef70203e45d72bc95ab4b" [metadata.files] aiofiles = [ @@ -1605,9 +1598,9 @@ importlib-metadata = [ {file = "importlib_metadata-5.2.0-py3-none-any.whl", hash = "sha256:0eafa39ba42bf225fc00e67f701d71f85aead9f878569caf13c3724f704b970f"}, {file = "importlib_metadata-5.2.0.tar.gz", hash = "sha256:404d48d62bba0b7a77ff9d405efd91501bef2e67ff4ace0bed40a0cf28c3c7cd"}, ] -inflect = [ - {file = "inflect-6.0.4-py3-none-any.whl", hash = "sha256:2d592e7e4eafb6e51f9c626c5dd4288f5ce55981eaac9b342e868ead95ead5c3"}, - {file = "inflect-6.0.4.tar.gz", hash = "sha256:1842649a17b6cad66812a5c9bdfacb6310e1e7b6dd8a31f026766df1b62612eb"}, +inflector = [ + {file = "Inflector-3.1.0-py3-none-any.whl", hash = "sha256:74b8f0f2e212c7129c26ad2058f82612a4a97ff45a7945d8eed2ff71b57e9a1b"}, + {file = "Inflector-3.1.0.tar.gz", hash = "sha256:0a9be5dd1646512f5ab602dcf8723787331594d822d02f382323963787043ee7"}, ] iniconfig = [ {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, diff --git a/pyproject.toml b/pyproject.toml index 77450dfb..58c50311 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,14 +23,13 @@ classifiers = [ [tool.poetry.dependencies] python = "^3.7" fastavro = "^1.7.3" -inflect = "^6.0.2" pytz = "^2023.2" dacite = "^1.8.0" faker = "^18.3.1" stringcase = "^1.2.0" -pydantic = {version = "^1.10.6", optional = true} -dc-avro = {version = "^0.6.3", optional = true} -faust-streaming = "^0.10.8" +inflector = "^3.1.0" +pydantic = {version = "^1.10.7", optional = true} +faust-streaming = {version = "^0.10.11", optional = true} [tool.poetry.group.dev.dependencies] mypy = "^1" @@ -47,12 +46,15 @@ mkdocs-material = "^9" [tool.poetry.group.ci-publish.dependencies] commitizen = "^2" +[tool.poetry.group.cli.dependencies] +dc-avro = "^0.6.4" + [tool.poetry.extras] pydantic = [ "pydantic", ] -cli = [ - "dc-avro", +faust = [ + "faust-streaming", ] [build-system] @@ -70,6 +72,10 @@ allow_empty_bodies = true module = "stringcase.*" ignore_missing_imports = true +[[tool.mypy.overrides]] +module = "inflector.*" +ignore_missing_imports = true + [tool.ruff] line-length = 120 select = [