diff --git a/.circleci/config.yml b/.circleci/config.yml index 21d08cff6..51e3976c7 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -48,8 +48,6 @@ dockerhub-auth-template: &DOCKERHUB_AUTH <<: *DOCKERHUB_CONTEXT - "build-image-fedora-35": <<: *DOCKERHUB_CONTEXT - - "build-image-oraclelinux-8": - <<: *DOCKERHUB_CONTEXT # Restore later as PyPy38 #- "build-image-pypy27-buster": # <<: *DOCKERHUB_CONTEXT @@ -88,10 +86,6 @@ workflows: - "ubuntu-22-04": {} - # Equivalent to RHEL 8; CentOS 8 is dead. - - "oraclelinux-8": - {} - - "nixos": name: "<>-<>" matrix: @@ -230,7 +224,7 @@ jobs: # version-specific binary packages so include the Python version # in this key, as well as the canonical source of our # dependencies. - - &CACHE_KEY "pip-packages-v1-<< parameters.pythonVersion >>-{{ checksum \"setup.py\" }}" + - &CACHE_KEY "pip-packages-v1-<< parameters.pythonVersion >>-{{ checksum \"pyproject.toml\" }}" - "run": name: "Fix $env:PATH" @@ -258,9 +252,6 @@ jobs: # doesn't cost us anything extra and saves us effort next time. name: "(Maybe) Build Wheels" command: | - python -m pip install setuptools # Some Pythons for Windows do not come with setuptools - python setup.py update_version # Cheat to win a race about writing _version.py - if ((Test-Path .\wheelhouse) -and (Test-Path .\wheelhouse\*)) { echo "Found populated wheelhouse, skipping wheel building." } else { @@ -279,7 +270,7 @@ jobs: name: "Install Dependencies" environment: # By this point we should no longer need an index. - PIP_NO_INDEX: "1" +## PIP_NO_INDEX: "1" command: | python -m pip install .[testenv] .[test] @@ -544,37 +535,6 @@ jobs: <<: *UTF_8_ENVIRONMENT TAHOE_LAFS_TOX_ENVIRONMENT: "py310" - oraclelinux-8: &RHEL_DERIV - docker: - - <<: *DOCKERHUB_AUTH - image: "tahoelafsci/oraclelinux:8-py3.8" - user: "nobody" - - environment: - <<: *UTF_8_ENVIRONMENT - TAHOE_LAFS_TOX_ENVIRONMENT: "py38" - - # pip cannot install packages if the working directory is not readable. - # We want to run a lot of steps as nobody instead of as root. - working_directory: "/tmp/project" - - steps: - - "checkout" - - run: *SETUP_VIRTUALENV - - run: *RUN_TESTS - - store_test_results: *STORE_TEST_RESULTS - - store_artifacts: *STORE_TEST_LOG - - store_artifacts: *STORE_ELIOT_LOG - - store_artifacts: *STORE_OTHER_ARTIFACTS - - run: *SUBMIT_COVERAGE - - fedora-35: - <<: *RHEL_DERIV - docker: - - <<: *DOCKERHUB_AUTH - image: "tahoelafsci/fedora:35-py3" - user: "nobody" - nixos: parameters: nixpkgs: @@ -699,14 +659,6 @@ jobs: PYTHON_VERSION: "3.10" - build-image-oraclelinux-8: - <<: *BUILD_IMAGE - - environment: - DISTRO: "oraclelinux" - TAG: "8" - PYTHON_VERSION: "3.8" - build-image-fedora-35: <<: *BUILD_IMAGE @@ -765,14 +717,6 @@ commands: steps: - "checkout" - - "run": - # The Nix package doesn't know how to do this part, unfortunately. - name: "Generate version" - command: | - nix-shell \ - -p 'python3.withPackages (ps: [ ps.setuptools ])' \ - --run 'python setup.py update_version' - - "run": name: "Build Package" environment: diff --git a/.circleci/create-virtualenv.sh b/.circleci/create-virtualenv.sh index 05ac64490..e1580de37 100755 --- a/.circleci/create-virtualenv.sh +++ b/.circleci/create-virtualenv.sh @@ -26,7 +26,7 @@ virtualenv --python "${PYTHON}" "${BOOTSTRAP_VENV}" PIP="${BOOTSTRAP_VENV}/bin/pip" # Tell pip where it can find any existing wheels. -export PIP_FIND_LINKS="file://${WHEELHOUSE_PATH}" +##export PIP_FIND_LINKS="file://${WHEELHOUSE_PATH}" # Get "certifi" to avoid bug #2913. Basically if a `setup_requires=...` causes # a package to be installed (with setuptools) then it'll fail on certain diff --git a/.circleci/populate-wheelhouse.sh b/.circleci/populate-wheelhouse.sh index 239c8367b..ae2f53f50 100755 --- a/.circleci/populate-wheelhouse.sh +++ b/.circleci/populate-wheelhouse.sh @@ -30,4 +30,5 @@ LANG="en_US.UTF-8" "${PIP}" \ wheel \ --wheel-dir "${WHEELHOUSE_PATH}" \ "${PROJECT_ROOT}"[testenv] \ - "${PROJECT_ROOT}"[test] + "${PROJECT_ROOT}"[test] \ + "${PROJECT_ROOT}"[build] diff --git a/.circleci/run-tests.sh b/.circleci/run-tests.sh index d897cc729..dc52dc5db 100755 --- a/.circleci/run-tests.sh +++ b/.circleci/run-tests.sh @@ -67,7 +67,7 @@ TIMEOUT="timeout --kill-after 1m 45m" # via tox and then scraping it out is hideous and failure prone. export SUBUNITREPORTER_OUTPUT_PATH="${SUBUNIT2}" export TAHOE_LAFS_TRIAL_ARGS="${TAHOE_LAFS_TRIAL_ARGS:---reporter=subunitv2-file --rterrors}" -export PIP_NO_INDEX="1" +##export PIP_NO_INDEX="1" # Make output unbuffered, so progress reports from subunitv2-file get streamed # and notify CircleCI we're still alive. diff --git a/.circleci/setup-virtualenv.sh b/.circleci/setup-virtualenv.sh index 7087c5120..fda4c438b 100755 --- a/.circleci/setup-virtualenv.sh +++ b/.circleci/setup-virtualenv.sh @@ -25,8 +25,8 @@ TAHOE_LAFS_TOX_ARGS=$1 shift || : # Tell pip where it can find any existing wheels. -export PIP_FIND_LINKS="file://${WHEELHOUSE_PATH}" -export PIP_NO_INDEX="1" +##export PIP_FIND_LINKS="file://${WHEELHOUSE_PATH}" +##export PIP_NO_INDEX="1" # Get everything else installed in it, too. "${BOOTSTRAP_VENV}"/bin/tox \ diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ce9ec61ee..88b385e2c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -71,7 +71,7 @@ jobs: - name: Install Python packages run: | - pip install --upgrade tox tox-gh-actions setuptools + pip install --upgrade tox tox-gh-actions pip list - name: Display tool versions @@ -95,13 +95,13 @@ jobs: - name: Upload eliot.log uses: actions/upload-artifact@v4 with: - name: "eliot-${{ matrix.os }}-Python-${{ matrix.python-version }}.log" + name: "eliot-${{ matrix.os }}-python-${{ matrix.python-version }}.log" path: eliot.log - name: Upload trial log uses: actions/upload-artifact@v4 with: - name: "test-${{ matrix.os }}-Python-${{ matrix.python-version }}.log" + name: "test-${{ matrix.os }}-python-${{ matrix.python-version }}.log" path: _trial_temp/test.log # Upload this job's coverage data to Coveralls. While there is a GitHub @@ -233,7 +233,7 @@ jobs: uses: actions/upload-artifact@v4 if: failure() with: - name: "integration.eliot-${{ matrix.os }}-Python-${{ matrix.python-version }}.json" + name: "integration.eliot-${{ matrix.os }}-python-${{ matrix.python-version }}.json" path: integration.eliot.json packaging: diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index 6cec1c847..000000000 --- a/MANIFEST.in +++ /dev/null @@ -1,13 +0,0 @@ -include README.rst -include COPYING.GPL COPYING.TGPPL.rst CREDITS Makefile NEWS.rst Tahoe.home -include relnotes.txt -include Dockerfile -include tox.ini .appveyor.yml .travis.yml -include .coveragerc -recursive-include src *.xhtml *.js *.png *.css *.svg *.txt *.yaml -graft docs -graft misc -graft static -graft integration - -global-exclude *~ *.pyc diff --git a/README.rst b/README.rst index bbf88610d..189dc12ad 100644 --- a/README.rst +++ b/README.rst @@ -56,7 +56,7 @@ Once ``tahoe --version`` works, see `How to Run Tahoe-LAFS `__ 🐍 Python 2 ----------- -Python 3.8 or later is required. +Python 3.9 or later is required. If you are still using Python 2.7, use Tahoe-LAFS version 1.17.1. diff --git a/integration/test_tor.py b/integration/test_tor.py index d114b763a..b5cfc6c7d 100644 --- a/integration/test_tor.py +++ b/integration/test_tor.py @@ -161,6 +161,6 @@ def test_anonymous_client(reactor, request, temp_dir, flog_gatherer, tor_network yield util.await_client_ready(normie) anonymoose = yield _create_anonymous_node(reactor, 'anonymoose', 8102, request, temp_dir, flog_gatherer, tor_network, introducer_furl, 1) - yield util.await_client_ready(anonymoose, minimum_number_of_servers=1, timeout=600) + yield util.await_client_ready(anonymoose, minimum_number_of_servers=1, timeout=1200) yield upload_to_one_download_from_the_other(reactor, temp_dir, normie, anonymoose) diff --git a/newsfragments/4133.installation b/newsfragments/4133.installation new file mode 100644 index 000000000..6e470d8f9 --- /dev/null +++ b/newsfragments/4133.installation @@ -0,0 +1 @@ +Now using the "hatch" build system, and pyproject.toml (exclusively) \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index fed528d4a..f8af1c065 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,3 +1,299 @@ +[project] +name = "tahoe-lafs" +dynamic = ["version"] +description = "secure, decentralized, fault-tolerant file store" +readme = "README.rst" +requires-python = ">=3.9" +license = "GPL-2.0-or-later" # see README.rst -- there is an alternative licence +authors = [ + { name = "the Tahoe-LAFS project", email = "tahoe-dev@lists.tahoe-lafs.org" } +] +#keywords = [ +# "privacy" +#] +classifiers = [ + "Development Status :: 5 - Production/Stable", + "Environment :: Console", + "Environment :: Web Environment", + "License :: OSI Approved :: GNU General Public License (GPL)", + "License :: DFSG approved", + "License :: Other/Proprietary License", + "Intended Audience :: Developers", + "Intended Audience :: End Users/Desktop", + "Intended Audience :: System Administrators", + "Operating System :: Microsoft", + "Operating System :: Microsoft :: Windows", + "Operating System :: Unix", + "Operating System :: POSIX :: Linux", + "Operating System :: POSIX", + "Operating System :: MacOS :: MacOS X", + "Operating System :: OS Independent", + "Natural Language :: English", + "Programming Language :: C", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Topic :: Utilities", + "Topic :: System :: Systems Administration", + "Topic :: System :: Filesystems", + "Topic :: System :: Distributed Computing", + "Topic :: Software Development :: Libraries", + "Topic :: System :: Archiving :: Backup", + "Topic :: System :: Archiving :: Mirroring", + "Topic :: System :: Archiving", +] +dependencies = [ + "zfec >= 1.1.0", + + # zope.interface >= 3.6.0 is required for Twisted >= 12.1.0. + "zope.interface >= 3.6.0", + + # * foolscap < 0.5.1 had a performance bug which spent O(N**2) CPU for + # transferring large mutable files of size N. + # * foolscap < 0.6 is incompatible with Twisted 10.2.0. + # * foolscap 0.6.1 quiets a DeprecationWarning. + # * foolscap < 0.6.3 is incompatible with Twisted 11.1.0 and newer. + # * foolscap 0.8.0 generates 2048-bit RSA-with-SHA-256 signatures, + # rather than 1024-bit RSA-with-MD5. This also allows us to work + # with a FIPS build of OpenSSL. + # * foolscap >= 0.12.3 provides tcp/tor/i2p connection handlers we need, + # and allocate_tcp_port + # * foolscap >= 0.12.5 has ConnectionInfo and ReconnectionInfo + # * foolscap >= 0.12.6 has an i2p.sam_endpoint() that takes kwargs + # * foolscap 0.13.2 drops i2p support completely + # * foolscap >= 21.7 is necessary for Python 3 with i2p support. + # * foolscap >= 23.3 is necessary for Python 3.11. + "foolscap >= 21.7.0", + "foolscap >= 23.3.0; python_version > '3.10'", + + # * cryptography 2.6 introduced some ed25519 APIs we rely on. Note that + # Twisted[conch] also depends on cryptography and Twisted[tls] + # transitively depends on cryptography. So it's anyone's guess what + # version of cryptography will *really* be installed. + "cryptography >= 2.6", + + # * Used for custom HTTPS validation + "pyOpenSSL >= 23.2.0", + + # * The SFTP frontend depends on Twisted 11.0.0 to fix the SSH server + # rekeying bug + # * The SFTP frontend and manhole depend on the conch extra. However, we + # can't explicitly declare that without an undesirable dependency on gmpy, + # as explained in ticket #2740. + # * Due to a setuptools bug, we need to declare a dependency on the tls + # extra even though we only depend on it via foolscap. + # * Twisted >= 15.1.0 is the first version that provided the [tls] extra. + # * Twisted-16.1.0 fixes https://twistedmatrix.com/trac/ticket/8223, + # which otherwise causes test_system to fail (DirtyReactorError, due to + # leftover timers) + # * Twisted-16.4.0 introduces `python -m twisted.trial` which is needed + # for coverage testing + # * Twisted 16.6.0 drops the undesirable gmpy dependency from the conch + # extra, letting us use that extra instead of trying to duplicate its + # dependencies here. Twisted[conch] >18.7 introduces a dependency on + # bcrypt. It is nice to avoid that if the user ends up with an older + # version of Twisted. That's hard to express except by using the extra. + # + # * Twisted 18.4.0 adds `client` and `host` attributes to `Request` in the + # * initializer, needed by logic in our custom `Request` subclass. + # + # In a perfect world, Twisted[conch] would be a dependency of an "sftp" + # extra. However, pip fails to resolve the dependencies all + # dependencies when asked for Twisted[tls] *and* Twisted[conch]. + # Specifically, "Twisted[conch]" (as the later requirement) is ignored. + # If there were an Tahoe-LAFS sftp extra that dependended on + # Twisted[conch] and install_requires only included Twisted[tls] then + # `pip install tahoe-lafs[sftp]` would not install requirements + # specified by Twisted[conch]. Since this would be the *whole point* of + # an sftp extra in Tahoe-LAFS, there is no point in having one. + # * Twisted 19.10 introduces Site.getContentFile which we use to get + # temporary upload files placed into a per-node temporary directory. + # * Twisted 22.8.0 added support for coroutine-returning functions in many + # places (mainly via `maybeDeferred`) + "Twisted[tls,conch] >= 22.8.0", + + "PyYAML >= 3.11", + + "six >= 1.10.0", + + # For 'tahoe invite' and 'tahoe join' + "magic-wormhole >= 0.10.2", + + # We want a new enough version to support custom JSON encoders. + "eliot >= 1.14.0", + + "pyrsistent", + + # A great way to define types of values. + "attrs >= 20.1.0", + + # WebSocket library for twisted and asyncio + "autobahn >= 22.4.3", + + # Support for Python 3 transition + "future >= 0.18.2", + + # Discover local network configuration + "netifaces", + + # Utility code: + "pyutil >= 3.3.0", + + # Linux distribution detection: + "distro >= 1.4.0", + + # For the RangeMap datastructure. Need 2.0.2 at least for bugfixes. + "collections-extended >= 2.0.2", + + # HTTP server and client + # Latest version is necessary to work with latest werkzeug: + "klein >= 23.5.0", + # 2.2.0 has a bug: https://github.com/pallets/werkzeug/issues/2465 + "werkzeug != 2.2.0", + "treq", + # 5.6.0 excluded because https://github.com/agronholm/cbor2/issues/208 + "cbor2 != 5.6.0", + + # 0.6 adds the ability to decode CBOR. 0.6.1 fixes PyPy. + "pycddl >= 0.6.1", + + # Command-line parsing + "click >= 8.1.1", + + # for pid-file support + "psutil", + "filelock", + + # Duplicate the Twisted pywin32 dependency here. See + # https://tahoe-lafs.org/trac/tahoe-lafs/ticket/2392 for some + # discussion. + "pywin32 != 226;sys_platform=='win32'" +] + + +[project.scripts] +tahoe = "allmydata.scripts.runner:run" +grid-manager = "allmydata.cli.grid_manager:grid_manager" + + +[project.urls] +Homepage = "https://tahoe-lafs.org/" +Documentation = "https://tahoe-lafs.readthedocs.org/" +"Source code" = "https://github.com/tahoe-lafs/tahoe-lafs/" + + +[project.optional-dependencies] +tor = [ + # 23.5 added support for custom TLS contexts in web_agent(), which is + # needed for the HTTP storage client to run over Tor. + "txtorcon >= 23.5.0", +] +i2p = [ + # txi2p has Python 3 support in master branch, but it has not been + # released -- see https://github.com/str4d/txi2p/issues/10. We + # could use a fork for Python 3 until txi2p's maintainers are back + # in action. For Python 2, we could continue using the txi2p + # version about which no one has complained to us so far. + "txi2p; python_version < '3.0'", + "txi2p-tahoe >= 0.3.5; python_version > '3.0'", +] +build = [ + "dulwich", + "gpg", + "hatchling", + "hatch-vcs" +] + +testenv = [ + # Pin all of these versions for the same reason you ever want to + # pin anything: to prevent new releases with regressions from + # introducing spurious failures into CI runs for whatever + # development work is happening at the time. The versions + # selected here are just the current versions at the time. + # Bumping them to keep up with future releases is fine as long + # as those releases are known to actually work. + "pip==23.3.1", + "wheel==0.41.3", + "subunitreporter==23.8.0", + "python-subunit==1.4.2", + "junitxml==0.7", + "coverage==7.2.5", +] + +# Here are the library dependencies of the test suite. +test = [ + "mock", + "pytest", + "pytest-twisted", + "hypothesis >= 3.6.1", + "towncrier", + "testtools", + "fixtures", + "beautifulsoup4", + "html5lib", + # Pin old version until + # https://github.com/paramiko/paramiko/issues/1961 is fixed. + "paramiko < 2.9", + "pytest-timeout", + # Does our OpenMetrics endpoint adhere to the spec: + "prometheus-client == 0.11.0", + + "tahoe-lafs[tor]", # our own "tor" extra + "tahoe-lafs[i2p]" # our own "i2p" extra +] + + + + +[tool.hatch.version] +source = "vcs" +tag-pattern = "tahoe-lafs-(.*)" + +[tool.hatch.build.hooks.vcs] +version-file = "src/allmydata/_version.py" + + [build-system] -requires = ["setuptools"] -build-backend = "setuptools.build_meta" +requires = ["hatchling", "hatch-vcs"] +build-backend = "hatchling.build" + +# https://github.com/ofek/hatch-vcs/issues/35#issuecomment-1452025896 +[tool.hatch.build] +include = [ + "src/", + "COPYING.GPL", + "COPYING.TGPPL.rst", + "CREDITS", + "Makefile", + "NEWS.rst", + "Tahoe.home", + "relnotes.txt", + "Dockerfile", + "tox.ini", + ".appveyor.yml", + ".travis.yml", + ".coveragerc", + "*.xhtml", + "*.png", + "*.css", + "*.svg", + "docs/", + "misc/", + "static/", + "integration/", + "src/allmydata/test/data/*.txt", + "src/allmydata/test/data/*.yaml" +] +exclude = [ + "*~", + "*.pyc", + "#*#", + "venv*/", + ".tox/" +] + +[tool.hatch.build.targets.wheel] +packages = ["src/allmydata"] diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 9415b3ab4..000000000 --- a/setup.cfg +++ /dev/null @@ -1,17 +0,0 @@ -[aliases] -build = update_version build -sdist = update_version sdist -install = update_version install -develop = update_version develop -bdist_egg = update_version bdist_egg -bdist_wheel = update_version bdist_wheel - -# This has been replaced by ruff (see .ruff.toml), which has same checks as -# flake8 plus many more, and is also faster. However, we're keeping this config -# in case people still use flake8 in IDEs, etc.. -[flake8] -# Enforce all pyflakes constraints, and also prohibit tabs for indentation. -# Reference: -# https://flake8.pycqa.org/en/latest/user/error-codes.html -# https://pycodestyle.pycqa.org/en/latest/intro.html#error-codes -select = F, W191 diff --git a/setup.py b/setup.py deleted file mode 100644 index 54bf4503f..000000000 --- a/setup.py +++ /dev/null @@ -1,452 +0,0 @@ -#! /usr/bin/env python -# -*- coding: utf-8 -*- -import sys - -# Tahoe-LAFS -- secure, distributed storage grid -# -# Copyright © 2006-2012 The Tahoe-LAFS Software Foundation -# -# This file is part of Tahoe-LAFS. -# -# See the docs/about.rst file for licensing information. - -import os, subprocess, re -from io import open - -basedir = os.path.dirname(os.path.abspath(__file__)) - -# locate our version number - -def read_version_py(infname): - try: - verstrline = open(infname, "rt").read() - except EnvironmentError: - return None - else: - VSRE = r"^verstr = ['\"]([^'\"]*)['\"]" - mo = re.search(VSRE, verstrline, re.M) - if mo: - return mo.group(1) - -VERSION_PY_FILENAME = 'src/allmydata/_version.py' -version = read_version_py(VERSION_PY_FILENAME) - -install_requires = [ - # importlib.resources.files and friends are new in Python 3.9. - "importlib_resources; python_version < '3.9'", - - "zfec >= 1.1.0", - - # zope.interface >= 3.6.0 is required for Twisted >= 12.1.0. - "zope.interface >= 3.6.0", - - # * foolscap < 0.5.1 had a performance bug which spent O(N**2) CPU for - # transferring large mutable files of size N. - # * foolscap < 0.6 is incompatible with Twisted 10.2.0. - # * foolscap 0.6.1 quiets a DeprecationWarning. - # * foolscap < 0.6.3 is incompatible with Twisted 11.1.0 and newer. - # * foolscap 0.8.0 generates 2048-bit RSA-with-SHA-256 signatures, - # rather than 1024-bit RSA-with-MD5. This also allows us to work - # with a FIPS build of OpenSSL. - # * foolscap >= 0.12.3 provides tcp/tor/i2p connection handlers we need, - # and allocate_tcp_port - # * foolscap >= 0.12.5 has ConnectionInfo and ReconnectionInfo - # * foolscap >= 0.12.6 has an i2p.sam_endpoint() that takes kwargs - # * foolscap 0.13.2 drops i2p support completely - # * foolscap >= 21.7 is necessary for Python 3 with i2p support. - # * foolscap >= 23.3 is necessary for Python 3.11. - "foolscap >= 21.7.0", - "foolscap >= 23.3.0; python_version > '3.10'", - - # * cryptography 2.6 introduced some ed25519 APIs we rely on. Note that - # Twisted[conch] also depends on cryptography and Twisted[tls] - # transitively depends on cryptography. So it's anyone's guess what - # version of cryptography will *really* be installed. - "cryptography >= 2.6", - - # * Used for custom HTTPS validation - "pyOpenSSL >= 23.2.0", - - # * The SFTP frontend depends on Twisted 11.0.0 to fix the SSH server - # rekeying bug - # * The SFTP frontend and manhole depend on the conch extra. However, we - # can't explicitly declare that without an undesirable dependency on gmpy, - # as explained in ticket #2740. - # * Due to a setuptools bug, we need to declare a dependency on the tls - # extra even though we only depend on it via foolscap. - # * Twisted >= 15.1.0 is the first version that provided the [tls] extra. - # * Twisted-16.1.0 fixes https://twistedmatrix.com/trac/ticket/8223, - # which otherwise causes test_system to fail (DirtyReactorError, due to - # leftover timers) - # * Twisted-16.4.0 introduces `python -m twisted.trial` which is needed - # for coverage testing - # * Twisted 16.6.0 drops the undesirable gmpy dependency from the conch - # extra, letting us use that extra instead of trying to duplicate its - # dependencies here. Twisted[conch] >18.7 introduces a dependency on - # bcrypt. It is nice to avoid that if the user ends up with an older - # version of Twisted. That's hard to express except by using the extra. - # - # * Twisted 18.4.0 adds `client` and `host` attributes to `Request` in the - # * initializer, needed by logic in our custom `Request` subclass. - # - # In a perfect world, Twisted[conch] would be a dependency of an "sftp" - # extra. However, pip fails to resolve the dependencies all - # dependencies when asked for Twisted[tls] *and* Twisted[conch]. - # Specifically, "Twisted[conch]" (as the later requirement) is ignored. - # If there were an Tahoe-LAFS sftp extra that dependended on - # Twisted[conch] and install_requires only included Twisted[tls] then - # `pip install tahoe-lafs[sftp]` would not install requirements - # specified by Twisted[conch]. Since this would be the *whole point* of - # an sftp extra in Tahoe-LAFS, there is no point in having one. - # * Twisted 19.10 introduces Site.getContentFile which we use to get - # temporary upload files placed into a per-node temporary directory. - # * Twisted 22.8.0 added support for coroutine-returning functions in many - # places (mainly via `maybeDeferred`) - "Twisted[tls,conch] >= 22.8.0", - - "PyYAML >= 3.11", - - "six >= 1.10.0", - - # For 'tahoe invite' and 'tahoe join' - "magic-wormhole >= 0.10.2", - - # We want a new enough version to support custom JSON encoders. - "eliot >= 1.14.0", - - "pyrsistent", - - # A great way to define types of values. - "attrs >= 20.1.0", - - # WebSocket library for twisted and asyncio - "autobahn >= 22.4.3", - - # Support for Python 3 transition - "future >= 0.18.2", - - # Discover local network configuration - "netifaces", - - # Utility code: - "pyutil >= 3.3.0", - - # Linux distribution detection: - "distro >= 1.4.0", - - # For the RangeMap datastructure. Need 2.0.2 at least for bugfixes. - "collections-extended >= 2.0.2", - - # HTTP server and client - # Latest version is necessary to work with latest werkzeug: - "klein >= 23.5.0", - # 2.2.0 has a bug: https://github.com/pallets/werkzeug/issues/2465 - "werkzeug != 2.2.0", - "treq", - # 5.6.0 excluded because https://github.com/agronholm/cbor2/issues/208 - "cbor2 != 5.6.0", - - # 0.6 adds the ability to decode CBOR. 0.6.1 fixes PyPy. - "pycddl >= 0.6.1", - - # Command-line parsing - "click >= 8.1.1", - - # for pid-file support - "psutil", - "filelock", -] - -tor_requires = [ - # 23.5 added support for custom TLS contexts in web_agent(), which is - # needed for the HTTP storage client to run over Tor. - "txtorcon >= 23.5.0", -] - -i2p_requires = [ - # txi2p has Python 3 support in master branch, but it has not been - # released -- see https://github.com/str4d/txi2p/issues/10. We - # could use a fork for Python 3 until txi2p's maintainers are back - # in action. For Python 2, we could continue using the txi2p - # version about which no one has complained to us so far. - "txi2p; python_version < '3.0'", - "txi2p-tahoe >= 0.3.5; python_version > '3.0'", -] - -if len(sys.argv) > 1 and sys.argv[1] == '--fakedependency': - del sys.argv[1] - install_requires += ["fakedependency >= 1.0.0"] - -from setuptools import find_packages, setup -from setuptools import Command -from setuptools.command import install - - -trove_classifiers=[ - "Development Status :: 5 - Production/Stable", - "Environment :: Console", - "Environment :: Web Environment", - "License :: OSI Approved :: GNU General Public License (GPL)", - "License :: DFSG approved", - "License :: Other/Proprietary License", - "Intended Audience :: Developers", - "Intended Audience :: End Users/Desktop", - "Intended Audience :: System Administrators", - "Operating System :: Microsoft", - "Operating System :: Microsoft :: Windows", - "Operating System :: Unix", - "Operating System :: POSIX :: Linux", - "Operating System :: POSIX", - "Operating System :: MacOS :: MacOS X", - "Operating System :: OS Independent", - "Natural Language :: English", - "Programming Language :: C", - "Programming Language :: Python", - "Programming Language :: Python :: 3", - "Topic :: Utilities", - "Topic :: System :: Systems Administration", - "Topic :: System :: Filesystems", - "Topic :: System :: Distributed Computing", - "Topic :: Software Development :: Libraries", - "Topic :: System :: Archiving :: Backup", - "Topic :: System :: Archiving :: Mirroring", - "Topic :: System :: Archiving", - ] - - -GIT_VERSION_BODY = ''' -# This _version.py is generated from git metadata by the tahoe setup.py. - -__pkgname__ = "%(pkgname)s" -real_version = "%(version)s" -full_version = "%(full)s" -branch = "%(branch)s" -verstr = "%(normalized)s" -__version__ = verstr -''' - -def run_command(args, cwd=None): - use_shell = sys.platform == "win32" - try: - p = subprocess.Popen(args, stdout=subprocess.PIPE, cwd=cwd, shell=use_shell) - except EnvironmentError as e: # if this gives a SyntaxError, note that Tahoe-LAFS requires Python 3.8+ - print("Warning: unable to run %r." % (" ".join(args),)) - print(e) - return None - stdout = p.communicate()[0].strip() - if p.returncode != 0: - print("Warning: %r returned error code %r." % (" ".join(args), p.returncode)) - return None - return stdout - - -def versions_from_git(tag_prefix): - # This runs 'git' from the directory that contains this file. That either - # means someone ran a setup.py command (and this code is in - # versioneer.py, thus the containing directory is the root of the source - # tree), or someone ran a project-specific entry point (and this code is - # in _version.py, thus the containing directory is somewhere deeper in - # the source tree). This only gets called if the git-archive 'subst' - # variables were *not* expanded, and _version.py hasn't already been - # rewritten with a short version string, meaning we're inside a checked - # out source tree. - - # versions_from_git (as copied from python-versioneer) returns strings - # like "1.9.0-25-gb73aba9-dirty", which means we're in a tree with - # uncommited changes (-dirty), the latest checkin is revision b73aba9, - # the most recent tag was 1.9.0, and b73aba9 has 25 commits that weren't - # in 1.9.0 . The narrow-minded NormalizedVersion parser that takes our - # output (meant to enable sorting of version strings) refuses most of - # that. Tahoe uses a function named suggest_normalized_version() that can - # handle "1.9.0.post25", so dumb down our output to match. - - try: - source_dir = os.path.dirname(os.path.abspath(__file__)) - except NameError as e: - # some py2exe/bbfreeze/non-CPython implementations don't do __file__ - print("Warning: unable to find version because we could not obtain the source directory.") - print(e) - return {} - stdout = run_command(["git", "describe", "--tags", "--dirty", "--always"], - cwd=source_dir) - if stdout is None: - # run_command already complained. - return {} - stdout = stdout.decode("ascii") - if not stdout.startswith(tag_prefix): - print("Warning: tag %r doesn't start with prefix %r." % (stdout, tag_prefix)) - return {} - version = stdout[len(tag_prefix):] - pieces = version.split("-") - if len(pieces) == 1: - normalized_version = pieces[0] - else: - normalized_version = "%s.post%s" % (pieces[0], pieces[1]) - - stdout = run_command(["git", "rev-parse", "HEAD"], cwd=source_dir) - if stdout is None: - # run_command already complained. - return {} - full = stdout.decode("ascii").strip() - if version.endswith("-dirty"): - full += "-dirty" - normalized_version += ".dev0" - - # Thanks to Jistanidiot at . - stdout = run_command(["git", "rev-parse", "--abbrev-ref", "HEAD"], cwd=source_dir) - branch = (stdout or b"unknown").decode("ascii").strip() - - # this returns native strings (bytes on py2, unicode on py3) - return {"version": version, "normalized": normalized_version, - "full": full, "branch": branch} - -# setup.cfg has an [aliases] section which runs "update_version" before many -# commands (like "build" and "sdist") that need to know our package version -# ahead of time. If you add different commands (or if we forgot some), you -# may need to add it to setup.cfg and configure it to run update_version -# before your command. - -class UpdateVersion(Command): - description = "update _version.py from revision-control metadata" - user_options = install.install.user_options - - def initialize_options(self): - pass - def finalize_options(self): - pass - def run(self): - global version - verstr = version - if os.path.isdir(os.path.join(basedir, ".git")): - verstr = self.try_from_git() - - if verstr: - self.distribution.metadata.version = verstr - else: - print("""\ -******************************************************************** -Warning: no version information found. This may cause tests to fail. -******************************************************************** -""") - - def try_from_git(self): - # If we change the release tag names, we must change this too - versions = versions_from_git("tahoe-lafs-") - - # setup.py might be run by either py2 or py3 (when run by tox, which - # uses py3 on modern debian/ubuntu distros). We want this generated - # file to contain native strings on both (str=bytes in py2, - # str=unicode in py3) - if versions: - body = GIT_VERSION_BODY % { - "pkgname": self.distribution.get_name(), - "version": versions["version"], - "normalized": versions["normalized"], - "full": versions["full"], - "branch": versions["branch"], - } - f = open(VERSION_PY_FILENAME, "wb") - f.write(body.encode("ascii")) - f.close() - print("Wrote normalized version %r into '%s'" % (versions["normalized"], VERSION_PY_FILENAME)) - - return versions.get("normalized", None) - -class PleaseUseTox(Command): - user_options = [] - def initialize_options(self): - pass - def finalize_options(self): - pass - - def run(self): - print("ERROR: Please use 'tox' to run the test suite.") - sys.exit(1) - -setup_args = {} -if version: - setup_args["version"] = version - -setup(name="tahoe-lafs", # also set in __init__.py - description='secure, decentralized, fault-tolerant file store', - long_description=open('README.rst', 'r', encoding='utf-8').read(), - author='the Tahoe-LAFS project', - author_email='tahoe-dev@lists.tahoe-lafs.org', - url='https://tahoe-lafs.org/', - license='GNU GPL', # see README.rst -- there is an alternative licence - cmdclass={"update_version": UpdateVersion, - "test": PleaseUseTox, - }, - package_dir = {'':'src'}, - packages=find_packages('src') + ['allmydata.test.plugins'], - classifiers=trove_classifiers, - # We support Python 3.8 or later, 3.13 is untested for now - python_requires=">=3.8, <3.13", - install_requires=install_requires, - extras_require={ - # Duplicate the Twisted pywin32 dependency here. See - # https://tahoe-lafs.org/trac/tahoe-lafs/ticket/2392 for some - # discussion. - ':sys_platform=="win32"': ["pywin32 != 226"], - "build": [ - "dulwich", - "gpg", - ], - - # Here are the dependencies required to set up a reproducible test - # environment. This could be for CI or local development. These - # are *not* library dependencies of the test suite itself. They are - # the tools we use to run the test suite at all. - "testenv": [ - # Pin all of these versions for the same reason you ever want to - # pin anything: to prevent new releases with regressions from - # introducing spurious failures into CI runs for whatever - # development work is happening at the time. The versions - # selected here are just the current versions at the time. - # Bumping them to keep up with future releases is fine as long - # as those releases are known to actually work. - "pip==23.3.1", - "wheel==0.41.3", - "subunitreporter==23.8.0", - "python-subunit==1.4.2", - "junitxml==0.7", - "coverage==7.2.5", - ], - - # Here are the library dependencies of the test suite. - "test": [ - "mock", - "pytest", - "pytest-twisted", - "hypothesis >= 3.6.1", - "towncrier", - "testtools", - "fixtures", - "beautifulsoup4", - "html5lib", - # Pin old version until - # https://github.com/paramiko/paramiko/issues/1961 is fixed. - "paramiko < 2.9", - "pytest-timeout", - # Does our OpenMetrics endpoint adhere to the spec: - "prometheus-client == 0.11.0", - ] + tor_requires + i2p_requires, - "tor": tor_requires, - "i2p": i2p_requires, - }, - package_data={"allmydata.web": ["*.xhtml", - "static/*.js", "static/*.png", "static/*.css", - "static/img/*.png", - "static/css/*.css", - ], - "allmydata": ["ported-modules.txt"], - }, - include_package_data=True, - entry_points={ - 'console_scripts': [ - 'tahoe = allmydata.scripts.runner:run', - 'grid-manager = allmydata.cli.grid_manager:grid_manager', - ] - }, - **setup_args - ) diff --git a/src/allmydata/web/common.py b/src/allmydata/web/common.py index cf6eaecff..832307ccd 100644 --- a/src/allmydata/web/common.py +++ b/src/allmydata/web/common.py @@ -4,11 +4,8 @@ Ported to Python 3. from __future__ import annotations from six import ensure_str -import sys -if sys.version_info[:2] >= (3, 9): - from importlib.resources import files as resource_files, as_file -else: - from importlib_resources import files as resource_files, as_file +from importlib.resources import files as resource_files +from importlib.resources import as_file from contextlib import ExitStack import weakref from typing import Optional, Union, TypeVar, overload diff --git a/tox.ini b/tox.ini index 5748928fe..d369d7de7 100644 --- a/tox.ini +++ b/tox.ini @@ -7,19 +7,17 @@ # the tox-gh-actions package. [gh-actions] python = - 3.8: py38-coverage 3.9: py39-coverage 3.10: py310-coverage 3.11: py311-coverage 3.12: py312-coverage - pypy-3.8: pypy38 pypy-3.9: pypy39 [pytest] twisted = 1 [tox] -envlist = typechecks,codechecks,py{38,39,310,311,312}-{coverage},pypy27,pypy38,pypy39,integration +envlist = typechecks,codechecks,py{39,310,311,312}-{coverage},pypy39,integration minversion = 4 [testenv] @@ -138,7 +136,7 @@ commands = # Different versions of Python have a different standard library, and we # want to be compatible with all the variations. For speed's sake we only do # the earliest and latest versions. - mypy --python-version=3.8 src + mypy --python-version=3.9 src mypy --python-version=3.12 src