From 1e5f56b58f0803f13a576f2dffe31382ebba9ff4 Mon Sep 17 00:00:00 2001 From: Iwan Aucamp Date: Tue, 13 Jun 2023 21:33:01 +0200 Subject: [PATCH] BREAKING CHANGE: drop support for python 3.7 (#2436) Python 3.7 will be end-of-life on the 27th of June 2023 and the next release of RDFLib will be a new major version. This changes the minimum supported version of Python to 3.8.1 as some of the dependencies we use are not too fond of python 3.8.0. This change also removes all accommodations for older python versions. --- .github/workflows/validate.yaml | 15 ++++------ README.md | 2 +- docs/conf.py | 5 +--- docs/developers.rst | 2 ++ docs/gettingstarted.rst | 2 +- docs/upgrade6to7.rst | 5 ++++ examples/secure_with_audit.py | 9 +----- poetry.lock | 50 ++----------------------------- pyproject.toml | 12 ++++---- rdflib/__init__.py | 7 +---- rdflib/_type_checking.py | 7 +---- rdflib/plugin.py | 7 +---- rdflib/plugins/sparql/__init__.py | 6 +--- test/conftest.py | 11 +++---- test/test_misc/test_security.py | 9 ++---- 15 files changed, 34 insertions(+), 115 deletions(-) diff --git a/.github/workflows/validate.yaml b/.github/workflows/validate.yaml index dc95a79b4..8044ef02f 100644 --- a/.github/workflows/validate.yaml +++ b/.github/workflows/validate.yaml @@ -25,30 +25,30 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"] + python-version: ["3.8", "3.9", "3.10", "3.11"] os: [ubuntu-latest, macos-latest, windows-latest] # This is used for injecting additional tests for a specific python # version and OS. suffix: [""] include: - - python-version: "3.7" + - python-version: "3.8" os: ubuntu-latest extensive-tests: true TOXENV_SUFFIX: "-docs" - - python-version: "3.7" + - python-version: "3.8" os: ubuntu-latest extensive-tests: true suffix: "-min" TOXENV_SUFFIX: "-min" - - python-version: "3.8" + - python-version: "3.9" os: ubuntu-latest TOX_EXTRA_COMMAND: "- isort --check-only --diff ." TOXENV_SUFFIX: "-docs" - - python-version: "3.9" + - python-version: "3.10" os: ubuntu-latest TOX_EXTRA_COMMAND: "- black --check --diff ./rdflib" TOXENV_SUFFIX: "-lxml" - - python-version: "3.10" + - python-version: "3.11" os: ubuntu-latest TOX_EXTRA_COMMAND: "flake8 --exit-zero rdflib" TOXENV_SUFFIX: "-docs" @@ -56,9 +56,6 @@ jobs: extensive-tests: true TOX_TEST_HARNESS: "firejail --net=none --" TOX_PYTEST_EXTRA_ARGS: "-m 'not webtest'" - - python-version: "3.11" - os: ubuntu-latest - TOXENV_SUFFIX: "-docs" steps: - uses: actions/checkout@v3 - name: Cache XDG_CACHE_HOME diff --git a/README.md b/README.md index b2a92d16a..c654a2700 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ Help with maintenance of all of the RDFLib family of packages is always welcome ## Versions & Releases -* `7.0.0a0` current `main` branch +* `7.0.0a0` current `main` branch and supports Python 3.8.1+ only. * `6.x.y` current release and support Python 3.7+ only. Many improvements over 5.0.0 * see [Releases](https://github.com/RDFLib/rdflib/releases) * `5.x.y` supports Python 2.7 and 3.4+ and is [mostly backwards compatible with 4.2.2](https://rdflib.readthedocs.io/en/stable/upgrade4to5.html). diff --git a/docs/conf.py b/docs/conf.py index add49fdfe..93d78d8a0 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -256,7 +256,7 @@ def find_version(filename): # Example configuration for intersphinx: refer to the Python standard library. intersphinx_mapping = { - "python": ("https://docs.python.org/3.7", None), + "python": ("https://docs.python.org/3.8", None), } html_experimental_html5_writer = True @@ -331,9 +331,6 @@ def find_version(filename): ] ) -if sys.version_info < (3, 8): - nitpick_ignore.extend([("py:class", "importlib_metadata.EntryPoint")]) - def autodoc_skip_member_handler( app: sphinx.application.Sphinx, diff --git a/docs/developers.rst b/docs/developers.rst index 759e017ea..d6cc67e2e 100644 --- a/docs/developers.rst +++ b/docs/developers.rst @@ -437,6 +437,8 @@ flag them as expecting to fail. Compatibility ------------- +RDFlib 7.0.0 release and later only support Python 3.8.1 and newer. + RDFlib 6.0.0 release and later only support Python 3.7 and newer. RDFLib 5.0.0 maintained compatibility with Python versions 2.7, 3.4, 3.5, 3.6, 3.7. diff --git a/docs/gettingstarted.rst b/docs/gettingstarted.rst index ec6573766..44307ae8a 100644 --- a/docs/gettingstarted.rst +++ b/docs/gettingstarted.rst @@ -51,7 +51,7 @@ methods that search triples and return them in arbitrary order. RDFLib graphs also redefine certain built-in Python methods in order to behave in a predictable way. They do this by `emulating container types -`_ and +`_ and are best thought of as a set of 3-item tuples ("triples", in RDF-speak): .. code-block:: text diff --git a/docs/upgrade6to7.rst b/docs/upgrade6to7.rst index c8847adbf..d58d25735 100644 --- a/docs/upgrade6to7.rst +++ b/docs/upgrade6to7.rst @@ -4,6 +4,11 @@ Upgrading 6 to 7 ============================================ +Python version +---------------------------------------------------- + +RDFLib 7 requires Python 3.8.1 or later. + New behaviour for ``publicID`` in ``parse`` methods. ---------------------------------------------------- diff --git a/examples/secure_with_audit.py b/examples/secure_with_audit.py index 434be5a49..f49ccd164 100644 --- a/examples/secure_with_audit.py +++ b/examples/secure_with_audit.py @@ -61,15 +61,8 @@ def main() -> None: ), ) - if sys.version_info < (3, 8): - logging.warn("This example requires Python 3.8 or higher") - return None - # Install the audit hook - # - # note on type error: This is needed because we are running mypy with python - # 3.7 mode, so mypy thinks the previous condition will always be true. - sys.addaudithook(audit_hook) # type: ignore[unreachable] + sys.addaudithook(audit_hook) graph = Graph() diff --git a/poetry.lock b/poetry.lock index 340769ca5..917b750df 100644 --- a/poetry.lock +++ b/poetry.lock @@ -76,7 +76,6 @@ packaging = ">=22.0" pathspec = ">=0.9.0" platformdirs = ">=2" tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} -typed-ast = {version = ">=1.4.2", markers = "python_version < \"3.8\" and implementation_name == \"cpython\""} typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""} [package.extras] @@ -193,7 +192,6 @@ files = [ [package.dependencies] colorama = {version = "*", markers = "platform_system == \"Windows\""} -importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} [[package]] name = "colorama" @@ -410,7 +408,6 @@ files = [ ] [package.dependencies] -typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""} zipp = ">=0.5" [package.extras] @@ -596,7 +593,6 @@ files = [ [package.dependencies] mdurl = ">=0.1,<1.0" -typing_extensions = {version = ">=3.7.4", markers = "python_version < \"3.8\""} [package.extras] benchmarking = ["psutil", "pytest", "pytest-benchmark"] @@ -746,7 +742,6 @@ files = [ [package.dependencies] mypy-extensions = ">=1.0.0" tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} -typed-ast = {version = ">=1.4.0,<2", markers = "python_version < \"3.8\""} typing-extensions = ">=3.10" [package.extras] @@ -784,7 +779,6 @@ markdown-it-py = ">=1.0.0,<3.0.0" mdit-py-plugins = ">=0.3.4,<0.4.0" pyyaml = "*" sphinx = ">=5,<7" -typing-extensions = {version = "*", markers = "python_version < \"3.8\""} [package.extras] code-style = ["pre-commit (>=3.0,<4.0)"] @@ -869,9 +863,6 @@ files = [ {file = "platformdirs-3.1.1.tar.gz", hash = "sha256:024996549ee88ec1a9aa99ff7f8fc819bb59e2c3477b410d90a16d32d6e707aa"}, ] -[package.dependencies] -typing-extensions = {version = ">=4.4", markers = "python_version < \"3.8\""} - [package.extras] docs = ["furo (>=2022.12.7)", "proselint (>=0.13)", "sphinx (>=6.1.3)", "sphinx-autodoc-typehints (>=1.22,!=1.23.4)"] test = ["appdirs (==1.4.4)", "covdefaults (>=2.2.2)", "pytest (>=7.2.1)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"] @@ -887,9 +878,6 @@ files = [ {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, ] -[package.dependencies] -importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} - [package.extras] dev = ["pre-commit", "tox"] testing = ["pytest", "pytest-benchmark"] @@ -958,7 +946,6 @@ files = [ [package.dependencies] colorama = {version = "*", markers = "sys_platform == \"win32\""} exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} -importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} iniconfig = "*" packaging = "*" pluggy = ">=0.12,<2.0" @@ -1284,39 +1271,6 @@ files = [ {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, ] -[[package]] -name = "typed-ast" -version = "1.5.4" -description = "a fork of Python 2 and 3 ast modules with type comment support" -optional = false -python-versions = ">=3.6" -files = [ - {file = "typed_ast-1.5.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:669dd0c4167f6f2cd9f57041e03c3c2ebf9063d0757dc89f79ba1daa2bfca9d4"}, - {file = "typed_ast-1.5.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:211260621ab1cd7324e0798d6be953d00b74e0428382991adfddb352252f1d62"}, - {file = "typed_ast-1.5.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:267e3f78697a6c00c689c03db4876dd1efdfea2f251a5ad6555e82a26847b4ac"}, - {file = "typed_ast-1.5.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c542eeda69212fa10a7ada75e668876fdec5f856cd3d06829e6aa64ad17c8dfe"}, - {file = "typed_ast-1.5.4-cp310-cp310-win_amd64.whl", hash = "sha256:a9916d2bb8865f973824fb47436fa45e1ebf2efd920f2b9f99342cb7fab93f72"}, - {file = "typed_ast-1.5.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:79b1e0869db7c830ba6a981d58711c88b6677506e648496b1f64ac7d15633aec"}, - {file = "typed_ast-1.5.4-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a94d55d142c9265f4ea46fab70977a1944ecae359ae867397757d836ea5a3f47"}, - {file = "typed_ast-1.5.4-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:183afdf0ec5b1b211724dfef3d2cad2d767cbefac291f24d69b00546c1837fb6"}, - {file = "typed_ast-1.5.4-cp36-cp36m-win_amd64.whl", hash = "sha256:639c5f0b21776605dd6c9dbe592d5228f021404dafd377e2b7ac046b0349b1a1"}, - {file = "typed_ast-1.5.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cf4afcfac006ece570e32d6fa90ab74a17245b83dfd6655a6f68568098345ff6"}, - {file = "typed_ast-1.5.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed855bbe3eb3715fca349c80174cfcfd699c2f9de574d40527b8429acae23a66"}, - {file = "typed_ast-1.5.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6778e1b2f81dfc7bc58e4b259363b83d2e509a65198e85d5700dfae4c6c8ff1c"}, - {file = "typed_ast-1.5.4-cp37-cp37m-win_amd64.whl", hash = "sha256:0261195c2062caf107831e92a76764c81227dae162c4f75192c0d489faf751a2"}, - {file = "typed_ast-1.5.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2efae9db7a8c05ad5547d522e7dbe62c83d838d3906a3716d1478b6c1d61388d"}, - {file = "typed_ast-1.5.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7d5d014b7daa8b0bf2eaef684295acae12b036d79f54178b92a2b6a56f92278f"}, - {file = "typed_ast-1.5.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:370788a63915e82fd6f212865a596a0fefcbb7d408bbbb13dea723d971ed8bdc"}, - {file = "typed_ast-1.5.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4e964b4ff86550a7a7d56345c7864b18f403f5bd7380edf44a3c1fb4ee7ac6c6"}, - {file = "typed_ast-1.5.4-cp38-cp38-win_amd64.whl", hash = "sha256:683407d92dc953c8a7347119596f0b0e6c55eb98ebebd9b23437501b28dcbb8e"}, - {file = "typed_ast-1.5.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4879da6c9b73443f97e731b617184a596ac1235fe91f98d279a7af36c796da35"}, - {file = "typed_ast-1.5.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3e123d878ba170397916557d31c8f589951e353cc95fb7f24f6bb69adc1a8a97"}, - {file = "typed_ast-1.5.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ebd9d7f80ccf7a82ac5f88c521115cc55d84e35bf8b446fcd7836eb6b98929a3"}, - {file = "typed_ast-1.5.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98f80dee3c03455e92796b58b98ff6ca0b2a6f652120c263efdba4d6c5e58f72"}, - {file = "typed_ast-1.5.4-cp39-cp39-win_amd64.whl", hash = "sha256:0fdbcf2fef0ca421a3f5912555804296f0b0960f0418c440f5d6d3abb549f3e1"}, - {file = "typed_ast-1.5.4.tar.gz", hash = "sha256:39e21ceb7388e4bb37f4c679d72707ed46c2fbf2a5609b8b8ebc4b067d977df2"}, -] - [[package]] name = "types-setuptools" version = "67.8.0.0" @@ -1389,5 +1343,5 @@ networkx = ["networkx"] [metadata] lock-version = "2.0" -python-versions = "^3.7" -content-hash = "36084be60ae6a80f19b7aab7044c7c7d6fb11a304dae08992060f46f1c457213" +python-versions = "^3.8.1" +content-hash = "1c56b77bc9381ed73f90bdc11243e8fae40be3fe06aec26c74eef94937698017" diff --git a/pyproject.toml b/pyproject.toml index 4d37e57c9..23c51b12c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,7 +11,6 @@ license = "BSD-3-Clause" classifiers=[ "Programming Language :: Python", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", @@ -39,10 +38,9 @@ rdfs2dot = 'rdflib.tools.rdfs2dot:main' rdfgraphisomorphism = 'rdflib.tools.graphisomorphism:main' [tool.poetry.dependencies] -python = "^3.7" +python = "^3.8.1" isodate = "^0.6.0" pyparsing = ">=2.1.0,<4" -importlib-metadata = {version = ">=4,<7", python = ">=3.7,<3.8"} berkeleydb = {version = "^18.1.0", optional = true} networkx = {version = "^2.0.0", optional = true} html5lib = {version = "^1.0", optional = true} @@ -69,9 +67,9 @@ sphinx-autodoc-typehints = "^1.17.1" typing-extensions = "^4.5.0" [tool.poetry.group.flake8.dependencies] -flake8 = {version = ">=4.0.1", python = ">=3.8"} # flakeheaven is incompatible with flake8 >=5.0 (https://github.com/flakeheaven/flakeheaven/issues/132) -flakeheaven = {version = "^3.2.1", python = ">=3.8"} -pep8-naming = {version = "^0.13.2", python = ">=3.8"} +flake8 = {version = ">=4.0.1"} # flakeheaven is incompatible with flake8 >=5.0 (https://github.com/flakeheaven/flakeheaven/issues/132) +flakeheaven = {version = "^3.2.1"} +pep8-naming = {version = "^0.13.2"} [tool.poetry.extras] berkeleydb = ["berkeleydb"] @@ -204,7 +202,7 @@ skip = [ [tool.mypy] files = ['rdflib', 'test', 'devtools', 'examples'] -python_version = "3.7" +python_version = "3.8" warn_unused_configs = true ignore_missing_imports = true disallow_subclassing_any = false diff --git a/rdflib/__init__.py b/rdflib/__init__.py index dc32be8ee..4677e0a95 100644 --- a/rdflib/__init__.py +++ b/rdflib/__init__.py @@ -44,12 +44,7 @@ """ import logging import sys - -if sys.version_info < (3, 8): - # importlib is only available in Python 3.8+; for 3.7 we must do this: - import importlib_metadata as metadata -else: - from importlib import metadata +from importlib import metadata _DISTRIBUTION_METADATA = metadata.metadata("rdflib") diff --git a/rdflib/_type_checking.py b/rdflib/_type_checking.py index ac6e2b8b8..c9e0202ea 100644 --- a/rdflib/_type_checking.py +++ b/rdflib/_type_checking.py @@ -14,18 +14,13 @@ and this module is not part the the RDFLib public API. """ -import sys - __all__ = [ "_NamespaceSetString", "_MulPathMod", ] -if sys.version_info >= (3, 8): - from typing import Literal as PyLiteral -else: - from typing_extensions import Literal as PyLiteral +from typing import Literal as PyLiteral _NamespaceSetString = PyLiteral["core", "rdflib", "none"] _MulPathMod = PyLiteral["*", "+", "?"] # noqa: F722 diff --git a/rdflib/plugin.py b/rdflib/plugin.py index 9d2f8540b..676ffbaa8 100644 --- a/rdflib/plugin.py +++ b/rdflib/plugin.py @@ -25,7 +25,7 @@ """ -import sys +from importlib.metadata import EntryPoint, entry_points from typing import ( TYPE_CHECKING, Any, @@ -52,11 +52,6 @@ from rdflib.serializer import Serializer from rdflib.store import Store -if sys.version_info < (3, 8): - from importlib_metadata import EntryPoint, entry_points -else: - from importlib.metadata import EntryPoint, entry_points - __all__ = [ "register", "get", diff --git a/rdflib/plugins/sparql/__init__.py b/rdflib/plugins/sparql/__init__.py index 011b7b591..a11a6e004 100644 --- a/rdflib/plugins/sparql/__init__.py +++ b/rdflib/plugins/sparql/__init__.py @@ -4,7 +4,7 @@ .. versionadded:: 4.0 """ -import sys +from importlib.metadata import entry_points from typing import TYPE_CHECKING SPARQL_LOAD_GRAPHS = True @@ -40,10 +40,6 @@ assert operators assert parserutils -if sys.version_info < (3, 8): - from importlib_metadata import entry_points -else: - from importlib.metadata import entry_points all_entry_points = entry_points() if hasattr(all_entry_points, "select"): diff --git a/test/conftest.py b/test/conftest.py index 38f4dabc1..01153f9fa 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -85,13 +85,10 @@ def function_httpmocks( @pytest.fixture(scope="session", autouse=True) -def audit_hook_dispatcher() -> Generator[Optional[AuditHookDispatcher], None, None]: - if sys.version_info >= (3, 8): - dispatcher = AuditHookDispatcher() - sys.addaudithook(dispatcher.audit) - yield dispatcher - else: - yield None +def audit_hook_dispatcher() -> Generator[AuditHookDispatcher, None, None]: + dispatcher = AuditHookDispatcher() + sys.addaudithook(dispatcher.audit) + yield dispatcher @pytest.fixture(scope="function") diff --git a/test/test_misc/test_security.py b/test/test_misc/test_security.py index b4c8fc229..652de6e73 100644 --- a/test/test_misc/test_security.py +++ b/test/test_misc/test_security.py @@ -8,7 +8,7 @@ from test.utils.httpfileserver import HTTPFileServer, ProtoFileResource from test.utils.urlopen import context_urlopener from textwrap import dedent -from typing import Any, Iterable, Optional, Tuple +from typing import Any, Iterable, Tuple from urllib.request import HTTPHandler, OpenerDirector, Request import pytest @@ -74,17 +74,12 @@ def generate_make_block_file_cases() -> Iterable[ParameterSet]: @pytest.mark.parametrize(["defence", "uri_kind"], generate_make_block_file_cases()) def test_block_file( tmp_path: Path, - audit_hook_dispatcher: Optional[AuditHookDispatcher], + audit_hook_dispatcher: AuditHookDispatcher, http_file_server: HTTPFileServer, exit_stack: ExitStack, defence: Defence, uri_kind: URIKind, ) -> None: - if audit_hook_dispatcher is None: - pytest.skip( - "audit hook dispatcher not available, likely because of Python version" - ) - context_file = tmp_path / "context.jsonld" context_file.write_text(dedent(JSONLD_CONTEXT)) context_file_served = http_file_server.add_file_with_caching(