From edb82a61bbc88c05dda5e0099f58d2dd65b68de9 Mon Sep 17 00:00:00 2001 From: Yasser Tahiri Date: Sat, 20 Apr 2024 17:28:33 +0100 Subject: [PATCH 01/11] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Refactor=20dependenc?= =?UTF-8?q?ies=20and=20requirements?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pyproject.toml | 15 +------------- requirements/all.txt | 3 +++ requirements/linting.in | 5 +++++ requirements/linting.txt | 41 ++++++++++++++++++++++++++++++++++++++ requirements/pyproject.txt | 22 ++++++++++++++++++++ requirements/testing.in | 5 +++++ requirements/testing.txt | 35 ++++++++++++++++++++++++++++++++ 7 files changed, 112 insertions(+), 14 deletions(-) create mode 100644 requirements/all.txt create mode 100644 requirements/linting.in create mode 100644 requirements/linting.txt create mode 100644 requirements/pyproject.txt create mode 100644 requirements/testing.in create mode 100644 requirements/testing.txt diff --git a/pyproject.toml b/pyproject.toml index fe70bbe..6bab57f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -38,8 +38,7 @@ classifiers = [ ] dependencies = [ - "pydantic >=1.6.2,!=1.7,!=1.7.1,!=1.7.2,!=1.7.3,!=1.8,!=1.8.1,<3.0.0", - "fastapi >=0.65.2,<0.110.2", + "fastapi >=0.100.0,<0.120.0", ] dynamic = ["version"] @@ -48,18 +47,6 @@ dynamic = ["version"] Homepage = "https://github.com/yezz123/fastapi-class" Funding = 'https://github.com/sponsors/yezz123' -[project.optional-dependencies] -lint = [ - "pre-commit==3.7.0", - "mypy==1.9.0", -] -test = [ - "requests==2.31.0", - "pytest==8.1.1", - "pytest-asyncio == 0.23.6", - "pytest-cov==5.0.0", - "pytest-pretty==1.2.0", -] [tool.hatch.version] path = "fastapi_class/__init__.py" diff --git a/requirements/all.txt b/requirements/all.txt new file mode 100644 index 0000000..fda4d7a --- /dev/null +++ b/requirements/all.txt @@ -0,0 +1,3 @@ +-r ./pyproject.txt +-r ./linting.txt +-r ./testing.txt diff --git a/requirements/linting.in b/requirements/linting.in new file mode 100644 index 0000000..fa59196 --- /dev/null +++ b/requirements/linting.in @@ -0,0 +1,5 @@ +pre-commit +mypy +black +pyupgrade +ruff diff --git a/requirements/linting.txt b/requirements/linting.txt new file mode 100644 index 0000000..fa46dc9 --- /dev/null +++ b/requirements/linting.txt @@ -0,0 +1,41 @@ +# This file was autogenerated by uv via the following command: +# uv pip compile requirements/linting.in -o requirements/linting.txt +black==24.4.0 +cfgv==3.4.0 + # via pre-commit +click==8.1.7 + # via black +distlib==0.3.8 + # via virtualenv +filelock==3.13.4 + # via virtualenv +identify==2.5.35 + # via pre-commit +mypy==1.9.0 +mypy-extensions==1.0.0 + # via + # black + # mypy +nodeenv==1.8.0 + # via pre-commit +packaging==24.0 + # via black +pathspec==0.12.1 + # via black +platformdirs==4.2.0 + # via + # black + # virtualenv +pre-commit==3.7.0 +pyupgrade==3.15.2 +pyyaml==6.0.1 + # via pre-commit +ruff==0.4.1 +setuptools==69.5.1 + # via nodeenv +tokenize-rt==5.2.0 + # via pyupgrade +typing-extensions==4.11.0 + # via mypy +virtualenv==20.25.3 + # via pre-commit diff --git a/requirements/pyproject.txt b/requirements/pyproject.txt new file mode 100644 index 0000000..505c1a8 --- /dev/null +++ b/requirements/pyproject.txt @@ -0,0 +1,22 @@ +# This file was autogenerated by uv via the following command: +# uv pip compile pyproject.toml -o requirements/pyproject.txt +annotated-types==0.6.0 + # via pydantic +anyio==4.3.0 + # via starlette +fastapi==0.110.2 +idna==3.7 + # via anyio +pydantic==2.7.0 + # via fastapi +pydantic-core==2.18.1 + # via pydantic +sniffio==1.3.1 + # via anyio +starlette==0.37.2 + # via fastapi +typing-extensions==4.11.0 + # via + # fastapi + # pydantic + # pydantic-core diff --git a/requirements/testing.in b/requirements/testing.in new file mode 100644 index 0000000..b47741e --- /dev/null +++ b/requirements/testing.in @@ -0,0 +1,5 @@ +requests +pytest +pytest-asyncio +pytest-cov +pytest-pretty diff --git a/requirements/testing.txt b/requirements/testing.txt new file mode 100644 index 0000000..c745ff4 --- /dev/null +++ b/requirements/testing.txt @@ -0,0 +1,35 @@ +# This file was autogenerated by uv via the following command: +# uv pip compile requirements/testing.in -o requirements/testing.txt +certifi==2024.2.2 + # via requests +charset-normalizer==3.3.2 + # via requests +coverage==7.4.4 + # via pytest-cov +idna==3.7 + # via requests +iniconfig==2.0.0 + # via pytest +markdown-it-py==3.0.0 + # via rich +mdurl==0.1.2 + # via markdown-it-py +packaging==24.0 + # via pytest +pluggy==1.4.0 + # via pytest +pygments==2.17.2 + # via rich +pytest==8.1.1 + # via + # pytest-asyncio + # pytest-cov + # pytest-pretty +pytest-asyncio==0.23.6 +pytest-cov==5.0.0 +pytest-pretty==1.2.0 +requests==2.31.0 +rich==13.7.1 + # via pytest-pretty +urllib3==2.2.1 + # via requests From 58e12e47357d3a507af552c81867387b92cc06d6 Mon Sep 17 00:00:00 2001 From: Yasser Tahiri Date: Sat, 20 Apr 2024 17:28:41 +0100 Subject: [PATCH 02/11] =?UTF-8?q?=E2=AC=86=20Update=20pre-commit=20hooks?= =?UTF-8?q?=20to=20latest=20versions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index dab2240..2c2a8cf 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.5.0 + rev: v4.6.0 hooks: - id: check-added-large-files - id: check-toml @@ -10,7 +10,7 @@ repos: - id: end-of-file-fixer - id: trailing-whitespace - repo: https://github.com/charliermarsh/ruff-pre-commit - rev: v0.2.0 + rev: v0.4.1 hooks: - id: ruff args: From dc2340a464555f8ad61d6597e7a164bac67ccfec Mon Sep 17 00:00:00 2001 From: Yasser Tahiri Date: Sat, 20 Apr 2024 17:29:04 +0100 Subject: [PATCH 03/11] =?UTF-8?q?=F0=9F=94=A8=20Update=20requirements=20sc?= =?UTF-8?q?ript=20to=20refresh=20dependencies?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/requirements.sh | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 scripts/requirements.sh diff --git a/scripts/requirements.sh b/scripts/requirements.sh new file mode 100644 index 0000000..e9263ee --- /dev/null +++ b/scripts/requirements.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash + +refresh-lockfiles() { + echo "Updating requirements/*.txt files using uv" + find requirements/ -name '*.txt' ! -name 'all.txt' -type f -delete + uv pip compile requirements/linting.in -o requirements/linting.txt + uv pip compile requirements/testing.in -o requirements/testing.txt + uv pip compile pyproject.toml -o requirements/pyproject.txt + uv pip install -r requirements/all.txt +} + +refresh-lockfiles From f3608d665ce2c50cfd2a6f3e612de3cf0585f6cf Mon Sep 17 00:00:00 2001 From: Yasser Tahiri Date: Sat, 20 Apr 2024 17:29:44 +0100 Subject: [PATCH 04/11] :bug: fix variables name --- fastapi_class/views.py | 35 ++++++++++++----------------------- 1 file changed, 12 insertions(+), 23 deletions(-) diff --git a/fastapi_class/views.py b/fastapi_class/views.py index 7c70bc4..851891b 100644 --- a/fastapi_class/views.py +++ b/fastapi_class/views.py @@ -10,9 +10,9 @@ from fastapi_class.routers import Metadata, Method COMMON_KEYWORD = "common" -RESPONSE_MODEL_ATTRIBUTE_NAME = "RESPONSE_MODEL" -RESPONSE_CLASS_ATTRIBUTE_NAME = "RESPONSE_CLASS" -ENDPOINT_METADATA_ATTRIBUTE_NAME = "ENDPOINT_METADATA" +RESPONSE_MODEL_ATTRIBUTE_NAME = "response_model" +RESPONSE_CLASS_ATTRIBUTE_NAME = "response_class" +ENDPOINT_METADATA_ATTRIBUTE_NAME = "__endpoint_metadata" EXCEPTIONS_ATTRIBUTE_NAME = "EXCEPTIONS" @@ -29,28 +29,17 @@ def View( name_parser: Callable[[object, str], str] = _view_class_name_default_parser, ): """ - Class-based view decorator. + Class-based view decorator for FastAPI. - :param router: router - :param path: path - :param default_status_code: default status code - :param name_parser: name parser + ### Example: + >>> from fastapi import FastAPI + >>> from fastapi_class import View - :raise AssertionError: if router is not an instance of FastAPI or APIRouter - - :example: - >>> from fastapi import FastAPI - >>> from fastapi_class import View - >>> app = FastAPI() - >>> @View(app) - ... class MyView: - ... def get(self): - ... return {"message": "Hello, world!"} - >>> app.include_router(MyView.router) - - Results: - - `GET /my-view` + >>> app = FastAPI() + >>> @View(app) + ... class MyView: + ... async def get(self): + ... return {"message": "Hello, world!"} """ def _decorator(cls) -> None: From a99c6751b65c118f9c1fccc355ccd212d02633a2 Mon Sep 17 00:00:00 2001 From: Yasser Tahiri Date: Sat, 20 Apr 2024 17:30:03 +0100 Subject: [PATCH 05/11] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Refactor=20HTTP=20me?= =?UTF-8?q?thods=20in=20ItemView=20class=20to=20be=20asynchronous?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- fastapi_class/__init__.py | 3 +-- fastapi_class/openapi.py | 7 +----- fastapi_class/routers.py | 52 +++++++++++++++++++++------------------ tests/test_views.py | 6 ++--- 4 files changed, 32 insertions(+), 36 deletions(-) diff --git a/fastapi_class/__init__.py b/fastapi_class/__init__.py index c86b0b9..dbef383 100644 --- a/fastapi_class/__init__.py +++ b/fastapi_class/__init__.py @@ -30,13 +30,12 @@ class ItemView: async def get(self, query: str = Query(), limit: int = 50, offset: int = 0): pass - def post(self, user: ItemModel): + async def post(self, user: ItemModel): pass ``` """ - __version__ = "3.5.0" from fastapi_class.exception import FormattedMessageException diff --git a/fastapi_class/openapi.py b/fastapi_class/openapi.py index 196e1e1..d79141f 100644 --- a/fastapi_class/openapi.py +++ b/fastapi_class/openapi.py @@ -21,12 +21,7 @@ def _exceptions_to_responses( """ Convert exceptions to responses. - :param exceptions: exceptions - :return: responses - - :raise TypeError: if exception is not an instance of HTTPException or a factory function - - :example: + ### example >>> from fastapi import HTTPException, status >>> from fastapi_class import _exceptions_to_responses >>> _exceptions_to_responses([HTTPException(status.HTTP_400_BAD_REQUEST, detail="Bad request")]) diff --git a/fastapi_class/routers.py b/fastapi_class/routers.py index 2bcb422..bed54f9 100644 --- a/fastapi_class/routers.py +++ b/fastapi_class/routers.py @@ -11,6 +11,10 @@ class Method(str, Enum): + """ + HTTP methods. + """ + GET = "get" POST = "post" PATCH = "patch" @@ -20,6 +24,10 @@ class Method(str, Enum): @dataclass(frozen=True, init=True, repr=True) class Metadata: + """ + Metadata class, used to store endpoint metadata. + """ + methods: Iterable[str | Method] name: str | None = None path: str | None = None @@ -29,6 +37,9 @@ class Metadata: __default_method_suffix: ClassVar[str] = "_or_default" def __getattr__(self, __name: str) -> Any | Callable[[Any], Any]: + """ + Dynamically return the value of the attribute. + """ if __name.endswith(Metadata.__default_method_suffix): prefix = __name.replace(Metadata.__default_method_suffix, "") if hasattr(self, prefix): @@ -47,30 +58,16 @@ def endpoint( response_class: type[Response] | None = None, ): """ - Endpoint decorator. - - :param methods: methods - :param name: name - :param path: path - :param status_code: status code - :param response_model: response model - :param response_class: response class - - :raise AssertionError: if response model or response class is not a subclass of BaseModel or Response respectively - :raise AssertionError: if methods is not an iterable of strings or Method enums - - :example: - >>> from fastapi import FastAPI - >>> from fastapi_class import endpoint - >>> app = FastAPI() - >>> @endpoint() - ... def get(): - ... return {"message": "Hello, world!"} - >>> app.include_router(get) - - Results: - - `GET /get` + Endpoint decorator for FastAPI. + + ### Example: + >>> from fastapi import FastAPI + >>> from fastapi_class import endpoint + >>> app = FastAPI() + >>> @endpoint() + ... async def get(): + ... return {"message": "Hello, world!"} + >>> app.include_router(get) """ assert all( issubclass(_type, expected_type) @@ -85,8 +82,15 @@ def endpoint( ), "Methods must be an string, iterable of strings or Method enums." def _decorator(function: Callable): + """ + Decorate the function. + """ + @wraps(function) async def _wrapper(*args, **kwargs): + """ + Wrapper for the function. + """ return await function(*args, **kwargs) parsed_method = set() diff --git a/tests/test_views.py b/tests/test_views.py index f19b1af..1f6e180 100644 --- a/tests/test_views.py +++ b/tests/test_views.py @@ -45,15 +45,13 @@ def _factory( endpoints = endpoints or [] for method in methods: - def dummy(self): - ... + def dummy(self): ... dummy.__name__ = method.value data[method.value] = dummy for _endpoint in endpoints: - def dummy(self): - ... + def dummy(self): ... data[_endpoint.get("alternative_name") or dummy.__name__] = _endpoint[ "decorator" From ce10b435059e3206f591b6b76627df883cc6ef13 Mon Sep 17 00:00:00 2001 From: Yasser Tahiri Date: Sat, 20 Apr 2024 17:34:02 +0100 Subject: [PATCH 06/11] =?UTF-8?q?=F0=9F=94=A7=20Update=20coverage=20paths?= =?UTF-8?q?=20in=20pyproject.toml?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pyproject.toml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 6bab57f..e9f4018 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -83,6 +83,17 @@ keep-runtime-typing = true plugins = "pydantic.mypy" follow_imports = "silent" +[tool.coverage.run] +source = ["fastapi_class"] +branch = true +context = '${CONTEXT}' + +[tool.coverage.paths] +source = [ + 'fastapi_class/', + '/Users/runner/work/fastapi_class/fastapi_class/fastapi_class/', + 'D:\a\fastapi_class\fastapi_class\fastapi_class', +] [tool.coverage.report] precision = 2 From d80500935f8f30df77a543a78ed563cac3ea21e1 Mon Sep 17 00:00:00 2001 From: Yasser Tahiri Date: Sat, 20 Apr 2024 17:34:20 +0100 Subject: [PATCH 07/11] =?UTF-8?q?=F0=9F=91=B7=20Refactor=20CI=20workflow?= =?UTF-8?q?=20to=20use=20setup-uv=20action?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci.yml | 34 ++++++++++++++++++++++++---------- scripts/test.sh | 2 +- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8c8589d..1b80c3d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,13 +20,17 @@ jobs: uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - - name: Install Dependencies - run: pip install -e .[lint] - - uses: pre-commit/action@v3.0.1 + + - name: setup uv + uses: yezz123/setup-uv@v4 with: - extra_args: --all-files --verbose - - name: Run mypy - run: bash scripts/lint.sh + uv-venv: ".venv" + + - name: Install Dependencies + run: uv pip install -r requirements/pyproject.txt && uv pip install -r requirements/linting.txt + + - name: Run Pre-commit + run: bash scripts/format.sh tests: @@ -51,17 +55,27 @@ jobs: with: python-version: ${{ matrix.python-version }} + - name: setup UV + uses: yezz123/setup-uv@v4 + with: + uv-venv: ".venv" + - name: Install Dependencies - run: pip install -e .[test] + run: uv pip install -r requirements/pyproject.txt && uv pip install -r requirements/testing.txt - name: Freeze Dependencies - run: pip freeze + run: uv pip freeze - - name: Test with pytest + - name: Test with pytest - ${{ matrix.os }} - py${{ matrix.python-version }} run: bash scripts/test.sh + env: + CONTEXT: ${{ runner.os }}-py${{ matrix.python-version }}-with-deps - - name: Upload coverage + - name: Upload coverage to Codecov uses: codecov/codecov-action@v4 + with: + token: ${{ secrets.CODECOV_TOKEN }} + file: ./coverage.xml # https://github.com/marketplace/actions/alls-green#why used for branch protection checks check: diff --git a/scripts/test.sh b/scripts/test.sh index b30ed17..bfee059 100644 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -6,4 +6,4 @@ set -x echo "ENV=${ENV}" export PYTHONPATH=. -pytest --cov=fastapi_class --cov=tests --cov-report=term-missing --cov-fail-under=80 +pytest --cov=fastapi_class --cov-report=xml From c84bff74cc5fd3bc22fccfb5a0f82afb529dbfba Mon Sep 17 00:00:00 2001 From: Yasser Tahiri Date: Sat, 20 Apr 2024 17:41:57 +0100 Subject: [PATCH 08/11] =?UTF-8?q?=F0=9F=94=A7=20include=20new=20Pydantic?= =?UTF-8?q?=20framework=20version?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index e9f4018..317c3a9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -25,6 +25,7 @@ classifiers = [ "Intended Audience :: Developers", "Framework :: FastAPI", "Framework :: Pydantic", + "Framework :: Pydantic :: 2", "Framework :: AsyncIO", "Programming Language :: Python", "Programming Language :: Python :: 3.8", From 92df4c939981144c4ab7b50f3e07b71764663db2 Mon Sep 17 00:00:00 2001 From: Yasser Tahiri Date: Sat, 20 Apr 2024 17:42:20 +0100 Subject: [PATCH 09/11] :memo: update documentation --- README.md | 48 +++++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index e887ea6..29c1e58 100644 --- a/README.md +++ b/README.md @@ -41,27 +41,25 @@ A common question people have as they become more comfortable with FastAPI is ho - Example: ```python -from fastapi import FastAPI, APIRouter, Query +from fastapi import FastAPI, Query from pydantic import BaseModel from fastapi_class import View app = FastAPI() -router = APIRouter() class ItemModel(BaseModel): id: int name: str description: str = None -@View(router) +@View(app) class ItemView: - def post(self, item: ItemModel): + async def post(self, item: ItemModel): return item - def get(self, item_id: int = Query(..., gt=0)): + async def get(self, item_id: int = Query(..., gt=0)): return {"item_id": item_id} -app.include_router(router) ``` ### Response model 📦 @@ -69,14 +67,13 @@ app.include_router(router) `Exception` in list need to be either function that return `fastapi.HTTPException` itself. In case of a function it is required to have all of it's arguments to be `optional`. ```py -from fastapi import FastAPI, APIRouter, HTTPException, status +from fastapi import FastAPI, HTTPException, status from fastapi.responses import PlainTextResponse from pydantic import BaseModel from fastapi_class import View app = FastAPI() -router = APIRouter() NOT_AUTHORIZED = HTTPException(401, "Not authorized.") NOT_ALLOWED = HTTPException(405, "Method not allowed.") @@ -85,7 +82,7 @@ NOT_FOUND = lambda item_id="item_id": HTTPException(404, f"Item with {item_id} n class ItemResponse(BaseModel): field: str | None = None -@View(router) +@View(app) class MyView: exceptions = { "__all__": [NOT_AUTHORIZED], @@ -100,29 +97,26 @@ class MyView: "delete": PlainTextResponse } - def get(self): + async def get(self): ... - def put(self): + async def put(self): ... - def delete(self): + async def delete(self): ... - -app.include_router(router) ``` ### Customized Endpoints ```py -from fastapi import FastAPI, APIRouter, HTTPException +from fastapi import FastAPI, HTTPException from fastapi.responses import PlainTextResponse from pydantic import BaseModel from fastapi_class import View, endpoint app = FastAPI() -router = APIRouter() NOT_AUTHORIZED = HTTPException(401, "Not authorized.") NOT_ALLOWED = HTTPException(405, "Method not allowed.") @@ -132,7 +126,7 @@ EXCEPTION = HTTPException(400, "Example.") class UserResponse(BaseModel): field: str | None = None -@View(router) +@View(app) class MyView: exceptions = { "__all__": [NOT_AUTHORIZED], @@ -149,17 +143,17 @@ class MyView: "delete": PlainTextResponse } - def get(self): + async def get(self): ... - def put(self): + async def put(self): ... - def delete(self): + async def delete(self): ... - @endpoint(("PUT",), path="edit") - def edit(self): + @endpoint(("PUT"), path="edit") + async def edit(self): ... ``` @@ -182,9 +176,17 @@ source venv/bin/activate And then install the development dependencies: +__Note:__ You should have `uv` installed, if not you can install it with: + +```bash +pip install uv +``` + +Then you can install the dependencies with: + ```bash # Install dependencies -pip install -e .[test,lint] +uv pip install -r requirements/all.txt ``` ### Run tests 🌝 From ff6cdcc51f3fbe746e3f44accdeaf0467fd13e2a Mon Sep 17 00:00:00 2001 From: Yasser Tahiri Date: Sat, 20 Apr 2024 17:42:34 +0100 Subject: [PATCH 10/11] =?UTF-8?q?=F0=9F=94=A7=20Add=20`Mypy`=20linting=20t?= =?UTF-8?q?o=20CI=20workflow?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1b80c3d..9fe6179 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,6 +32,9 @@ jobs: - name: Run Pre-commit run: bash scripts/format.sh + - name: Run Mypy + run: bash scripts/lint.sh + tests: name: test py${{ matrix.python-version }} on ${{ matrix.os }} From 680b9b129bc729941804328041576dc03e336f07 Mon Sep 17 00:00:00 2001 From: Yasser Tahiri Date: Sat, 20 Apr 2024 17:44:53 +0100 Subject: [PATCH 11/11] =?UTF-8?q?=F0=9F=94=96=20Release=20version=203.6.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- fastapi_class/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastapi_class/__init__.py b/fastapi_class/__init__.py index dbef383..f41162f 100644 --- a/fastapi_class/__init__.py +++ b/fastapi_class/__init__.py @@ -36,7 +36,7 @@ async def post(self, user: ItemModel): """ -__version__ = "3.5.0" +__version__ = "3.6.0" from fastapi_class.exception import FormattedMessageException from fastapi_class.openapi import ExceptionModel, _exceptions_to_responses