diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 9cc136a..30ed952 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -10,9 +10,9 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python 3.10 - uses: actions/setup-python@v3 + uses: actions/setup-python@v4 with: python-version: '3.10' - name: Build wheel and source tarball diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 355a94d..099e917 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -13,9 +13,9 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python 3.10 - uses: actions/setup-python@v3 + uses: actions/setup-python@v4 with: python-version: '3.10' - name: Install dependencies diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index c471166..66fe306 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -15,10 +15,10 @@ jobs: max-parallel: 10 matrix: sql-alchemy: [ "1.2", "1.3", "1.4","2.0" ] - python-version: [ "3.7", "3.8", "3.9", "3.10" ] + python-version: [ "3.9", "3.10", "3.11", "3.12", "3.13"] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v3 with: @@ -34,7 +34,7 @@ jobs: TOXENV: ${{ matrix.toxenv }} - name: Upload coverage.xml if: ${{ matrix.sql-alchemy == '1.4' && matrix.python-version == '3.10' }} - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: graphene-sqlalchemy-coverage path: coverage.xml diff --git a/graphene_sqlalchemy/__init__.py b/graphene_sqlalchemy/__init__.py index f0e7a45..69bb79b 100644 --- a/graphene_sqlalchemy/__init__.py +++ b/graphene_sqlalchemy/__init__.py @@ -2,7 +2,7 @@ from .types import SQLAlchemyInterface, SQLAlchemyObjectType from .utils import get_query, get_session -__version__ = "3.0.0rc1" +__version__ = "3.0.0rc2" __all__ = [ "__version__", diff --git a/graphene_sqlalchemy/converter.py b/graphene_sqlalchemy/converter.py index efcf3c6..6502412 100644 --- a/graphene_sqlalchemy/converter.py +++ b/graphene_sqlalchemy/converter.py @@ -7,6 +7,7 @@ from sqlalchemy import types as sqa_types from sqlalchemy.dialects import postgresql +from sqlalchemy.ext.hybrid import hybrid_property from sqlalchemy.orm import ( ColumnProperty, RelationshipProperty, @@ -14,7 +15,6 @@ interfaces, strategies, ) -from sqlalchemy.ext.hybrid import hybrid_property import graphene from graphene.types.json import JSONString diff --git a/graphene_sqlalchemy/filters.py b/graphene_sqlalchemy/filters.py index bb42272..cbe3d09 100644 --- a/graphene_sqlalchemy/filters.py +++ b/graphene_sqlalchemy/filters.py @@ -423,6 +423,13 @@ class Meta: graphene_type = graphene.Date +class DateTimeFilter(OrderedFilter): + """Concrete Filter Class which specifies a type for all the abstract filter methods defined in the super classes""" + + class Meta: + graphene_type = graphene.DateTime + + class IdFilter(FieldFilter): class Meta: graphene_type = graphene.ID diff --git a/graphene_sqlalchemy/tests/test_filters.py b/graphene_sqlalchemy/tests/test_filters.py index 4acf89a..87bbcea 100644 --- a/graphene_sqlalchemy/tests/test_filters.py +++ b/graphene_sqlalchemy/tests/test_filters.py @@ -1199,3 +1199,30 @@ async def test_additional_filters(session): schema = graphene.Schema(query=Query) result = await schema.execute_async(query, context_value={"session": session}) assert_and_raise_result(result, expected) + + +@pytest.mark.asyncio +async def test_do_not_create_filters(): + class WithoutFilters(SQLAlchemyObjectType): + class Meta: + abstract = True + + @classmethod + def __init_subclass_with_meta__(cls, _meta=None, **options): + super().__init_subclass_with_meta__( + _meta=_meta, create_filters=False, **options + ) + + class PetType(WithoutFilters): + class Meta: + model = Pet + name = "Pet" + interfaces = (relay.Node,) + connection_class = Connection + + class Query(graphene.ObjectType): + pets = SQLAlchemyConnectionField(PetType.connection) + + schema = graphene.Schema(query=Query) + + assert "filter" not in str(schema).lower() diff --git a/graphene_sqlalchemy/types.py b/graphene_sqlalchemy/types.py index 7053988..894ebfd 100644 --- a/graphene_sqlalchemy/types.py +++ b/graphene_sqlalchemy/types.py @@ -440,6 +440,7 @@ def __init_subclass_with_meta__( batching=False, connection_field_factory=None, _meta=None, + create_filters=True, **options, ): # We always want to bypass this hook unless we're defining a concrete @@ -474,7 +475,7 @@ def __init_subclass_with_meta__( only_fields=only_fields, exclude_fields=exclude_fields, batching=batching, - create_filters=True, + create_filters=create_filters, connection_field_factory=connection_field_factory, ) @@ -512,7 +513,7 @@ def __init_subclass_with_meta__( _meta.fields = sqla_fields # Save Generated filter class in Meta Class - if not _meta.filter_class: + if create_filters and not _meta.filter_class: # Map graphene fields to filters # TODO we might need to pass the ORMFields containing the SQLAlchemy models # to the scalar filters here (to generate expressions from the model) diff --git a/graphene_sqlalchemy/utils.py b/graphene_sqlalchemy/utils.py index 3ba1486..17d774d 100644 --- a/graphene_sqlalchemy/utils.py +++ b/graphene_sqlalchemy/utils.py @@ -3,9 +3,10 @@ import warnings from collections import OrderedDict from functools import _c3_mro +from importlib.metadata import version as get_version from typing import Any, Callable, Dict, Optional -import pkg_resources +from packaging import version from sqlalchemy import select from sqlalchemy.exc import ArgumentError from sqlalchemy.orm import class_mapper, object_mapper @@ -22,16 +23,12 @@ def get_nullable_type(_type): def is_sqlalchemy_version_less_than(version_string): """Check the installed SQLAlchemy version""" - return pkg_resources.get_distribution( - "SQLAlchemy" - ).parsed_version < pkg_resources.parse_version(version_string) + return version.parse(get_version("SQLAlchemy")) < version.parse(version_string) def is_graphene_version_less_than(version_string): # pragma: no cover """Check the installed graphene version""" - return pkg_resources.get_distribution( - "graphene" - ).parsed_version < pkg_resources.parse_version(version_string) + return version.parse(get_version("graphene")) < version.parse(version_string) SQL_VERSION_HIGHER_EQUAL_THAN_1_4 = False diff --git a/setup.py b/setup.py index fdace11..33eabcb 100644 --- a/setup.py +++ b/setup.py @@ -17,6 +17,7 @@ "promise>=2.3", "SQLAlchemy>=1.1", "aiodataloader>=0.2.0,<1.0", + "packaging>=23.0", ] tests_require = [ @@ -48,13 +49,14 @@ "Intended Audience :: Developers", "Topic :: Software Development :: Libraries", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", "Programming Language :: Python :: Implementation :: PyPy", ], - keywords="api graphql protocol rest relay graphene", + keywords="api graphql protocol rest relay graphene sqlalchemy", packages=find_packages(exclude=["tests"]), install_requires=requirements, extras_require={ diff --git a/tox.ini b/tox.ini index 9ce901e..6ec4699 100644 --- a/tox.ini +++ b/tox.ini @@ -1,14 +1,15 @@ [tox] -envlist = pre-commit,py{37,38,39,310}-sql{12,13,14,20} +envlist = pre-commit,py{39,310,311,312,313}-sql{12,13,14,20} skipsdist = true minversion = 3.7.0 [gh-actions] python = - 3.7: py37 - 3.8: py38 3.9: py39 3.10: py310 + 3.11: py311 + 3.12: py312 + 3.13: py313 [gh-actions:env] SQLALCHEMY =