diff --git a/.coveragerc b/.coveragerc deleted file mode 100644 index 7044b3309..000000000 --- a/.coveragerc +++ /dev/null @@ -1,25 +0,0 @@ -# .coveragerc to control coverage.py -[run] -source = qbittorrentapi -omit = qbittorrentapi/_attrdict.py -branch = True - -[report] -show_missing = True -skip_covered = True -exclude_lines = - # search categories was deprecated - class SearchCategoriesList - def search_categories - # defaults to exclude - pragma: no cover - def __repr__ - if self.debug: - if settings.DEBUG - raise AssertionError - raise NotImplementedError - if 0: - if __name__ == .__main__.: - -[html] -skip_empty = True diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 21b86cb77..565d6d384 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,9 +12,9 @@ on: workflow_dispatch: env: - LATEST_PYTHON_VER: "3.10" + LATEST_PYTHON_VER: "3.11" LATEST_QBT_VER: "v4.4.5" - SUBMIT_COVERAGE_VERSIONS: "2.7, 3.10" + SUBMIT_COVERAGE_VERSIONS: '[ "3.11" ]' QBITTORRENTAPI_HOST: "localhost:8080" QBITTORRENTAPI_PASSWORD: "adminadmin" QBITTORRENTAPI_USERNAME: "admin" @@ -32,26 +32,24 @@ jobs: steps: - name: Declare Latest qBittorrent Version id: set-qbittorrent-latest-version - run: echo "::set-output name=qbittorrent-latest-version::${{ env.LATEST_QBT_VER }}" + run: echo "qbittorrent-latest-version=${{ env.LATEST_QBT_VER }}" >> ${GITHUB_OUTPUT} - name: Declare Latest Python Version id: set-python-latest-version - run: echo "::set-output name=python-latest-version::${{ env.LATEST_PYTHON_VER }}" - - - name: Branch - run: echo Branch ${{ github.ref }} ${{ github.head_ref }} + run: echo "python-latest-version=${{ env.LATEST_PYTHON_VER }}" >> ${GITHUB_OUTPUT} - name: Checkout Repo - uses: actions/checkout@v3 + uses: actions/checkout@v3.1.0 - name: Set up Python ${{ env.LATEST_PYTHON_VER }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v4.3.0 with: python-version: ${{ env.LATEST_PYTHON_VER }} cache: 'pip' check-latest: true + cache-dependency-path: ${{ github.workspace }}/setup.cfg - - name: Lint with Pre-commit + - name: Lint uses: pre-commit/action@v3.0.0 Tests: @@ -60,13 +58,18 @@ jobs: runs-on: ubuntu-latest continue-on-error: true timeout-minutes: 10 + env: + IS_QBT_DEV: ${{ matrix.IS_QBT_DEV }} + QBT_VER: ${{ matrix.QBT_VER }} strategy: matrix: PYTHON_VER: [ "${{ needs.verify.outputs.python-latest-version }}" ] QBT_VER: [ v4.4.4, v4.3.9, v4.3.5, v4.3.4.1, v4.3.3, v4.3.2, v4.3.1, v4.3.0.1, v4.2.5, v4.2.0, v4.1.6, v4.1.0 ] include: # test all python versions against latest qBittorrent - - PYTHON_VER: "3.11-dev" + # - PYTHON_VER: "3.12-dev" + # QBT_VER: ${{ needs.verify.outputs.qbittorrent-latest-version }} + - PYTHON_VER: "3.11" QBT_VER: ${{ needs.verify.outputs.qbittorrent-latest-version }} - PYTHON_VER: "3.10" QBT_VER: ${{ needs.verify.outputs.qbittorrent-latest-version }} @@ -100,38 +103,40 @@ jobs: PYTHON_VER: ${{ needs.verify.outputs.python-latest-version }} steps: - name: Checkout Repo - uses: actions/checkout@v3 + uses: actions/checkout@v3.1.0 - name: Set up Python ${{ matrix.PYTHON_VER }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v4.3.0 with: python-version: ${{ matrix.PYTHON_VER }} cache: 'pip' check-latest: true + cache-dependency-path: ${{ github.workspace }}/setup.cfg - name: Start qBittorrent ${{ matrix.QBT_VER }} run: docker run ${{ env.DOCKER_ARGS }} ${{ env.DOCKER_IMAGE_NAME }}:${{ matrix.QBT_VER }}-debug - - name: Test with pytest - run: | - pip install .[test] - IS_QBT_DEV=${{ matrix.IS_QBT_DEV }} - QBT_VER=${{ matrix.QBT_VER }} - pytest + - name: Install + run: pip install .[test] + + - name: Test + run: pytest - name: qBittorrent Log run: docker logs qbt - name: Upload Coverage to Codecov - if: ((contains(env.SUBMIT_COVERAGE_VERSIONS, matrix.PYTHON_VER)) && ((github.event_name == 'pull_request') || (github.event_name == 'push'))) - uses: codecov/codecov-action@v3 + if: | + contains(fromJson(env.SUBMIT_COVERAGE_VERSIONS), matrix.PYTHON_VER) + && contains(fromJson('["push", "pull_request"]'), github.event_name) + uses: codecov/codecov-action@v3.1.1 with: fail_ci_if_error: true token: ${{ secrets.CODECOV_TOKEN }} - name: Send mail if: failure() - uses: dawidd6/action-send-mail@v3 + uses: dawidd6/action-send-mail@v3.7.1 with: server_address: smtp.gmail.com server_port: 587 @@ -153,13 +158,14 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Repo - uses: actions/checkout@v3 + uses: actions/checkout@v3.1.0 - name: Set up Python ${{ env.LATEST_PYTHON_VER }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v4.3.0 with: python-version: ${{ env.LATEST_PYTHON_VER }} cache: 'pip' + cache-dependency-path: ${{ github.workspace }}/setup.cfg - name: Install Build Tools run: python -m pip install -U pip setuptools wheel twine build @@ -185,13 +191,14 @@ jobs: os: ["ubuntu-latest", "windows-latest", "macos-latest"] steps: - name: Checkout Repo - uses: actions/checkout@v3 + uses: actions/checkout@v3.1.0 - name: Set up Python ${{ env.LATEST_PYTHON_VER }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v4.3.0 with: python-version: ${{ env.LATEST_PYTHON_VER }} cache: 'pip' + cache-dependency-path: ${{ github.workspace }}/setup.cfg - name: Install in Dev Mode run: | @@ -210,16 +217,17 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Repo - uses: actions/checkout@v3 + uses: actions/checkout@v3.1.0 - name: Set up Python ${{ env.LATEST_PYTHON_VER }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v4.3.0 with: python-version: ${{ env.LATEST_PYTHON_VER }} cache: 'pip' + cache-dependency-path: ${{ github.workspace }}/setup.cfg - - name: Install Doc Build Requirements - run: python -m pip install -r requirements-dev.txt + - name: Install requirements + run: python -m pip install .[dev] - name: Build Docs run: | diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 000000000..3514e0c1e --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,29 @@ +# .readthedocs.yaml +# Read the Docs configuration file +# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details + +# Required +version: 2 + +# Set the version of Python and other tools you might need +build: + os: ubuntu-22.04 + tools: + python: "3.11" + +# Build documentation in the docs/ directory with Sphinx +sphinx: + builder: html + configuration: docs/source/conf.py + +# If using Sphinx, optionally build your docs in additional formats such as PDF +# formats: +# - pdf + +# Optionally declare the Python requirements required to build your docs +python: + install: + - method: pip + path: . + extra_requirements: + - dev diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 000000000..a51dc9e9b --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,214 @@ +Change log +========== +### v2022.10.39 (26 oct 2022) +- Advertise support for Python 3.11 + +### v2022.8.38 (31 aug 2022) +- Advertise support for qBittorrent v4.4.5 + +### v2022.8.37 (24 aug 2022) +- Advertise support for qBittorrent v4.4.4 + +### v2022.8.36 (15 aug 2022) +- Comply with enforced HTTP method requirements from qBittorrent + +### v2022.8.35 (13 aug 2022) +- Remove ``PYTHON_`` prefix for configuration environment variables + +### v2022.8.34 (11 aug 2022) +- Add ``setuptools`` as an explicit dependency for ``pkg_resources.parse_version()`` + +### v2022.7.33 (27 jul 2022) +- Reorder class hierarchy to allow independent MixIn use +- Clean up typing annotations +- Optimize Dictionary and List initializations +- Rename Alias decorator to alias for better conformity + +### v2022.5.32 (30 may 2022) +- Implement pre-commit checks +- Advertise support for qBittorrent 4.4.3.1 + +### v2022.5.31 (24 may 2022) +- Advertise support for qBittorrent 4.4.3 +- Revamp GitHub CI +- Reorg ``Request`` for some more clarity (hopefully) + +### v2022.4.30 (3 apr 2022) +- Stop advertising support for Python 3.6 (EOL 12/2021) +- Publish to PyPI using API token and cleanup GitHub Action scripts + +### v2022.3.29 (25 mar 2022) +- Advertise support for qBittorrent v4.4.2 + +### v2022.2.28 (17 feb 2022) +- Advertise support for qBittorrent v4.4.1 +- qBittorrent reverted the category dictionary key ``savePath`` back to ``save_path`` + +### v2022.1.27 (9 jan 2022) +- Support for qBittorrent v4.4.0 +- ``torrents/info`` results can now be filtered by a torrent tag +- Added new torrent state "Forced Metadata Downloading" +- Support per-torrent/per-category "download folder" + +### v2021.12.26 (11 dec 2021) +- Stop sending ``Origin`` and ``Referer`` headers (Fixes #63) + +### v2021.12.25 (10 dec 2021) +- Close files that are opened and sent to Requests when adding torrents from files +- Enable warnings for tests and explicitly close Requests Sessions to prevent (mostly spurious) ResourceWarnings + +### v2021.12.24 (3 dec 2021) +- Add Type Hints for all public and private functions, methods, and variables +- Support HTTP timeouts as well as arbitrary Requests configurations + +### v2021.8.23 (28 aug 2021) +- Advertise support for qBittorrent 4.3.8 +- Drop support for Python 3.5 + +### v2021.5.22 (12 may 2021) +- Support for qBittorrent v4.3.5 +- ``torrents/files`` includes ``index`` for each file; ``index`` officially replaces ``id`` but ``id`` will still be populated + +### v2021.5.21 (1 may 2021) +- Allow users to force a specific communications scheme with ``FORCE_SCHEME_FROM_HOST`` (fixes #54) + +### v2021.4.20 (11 apr 2021) +- Add support for ratio limit and seeding time limit when adding torrents + +### v2021.4.19 (8 apr 2021) +- Update license in setup to match gpl->mit license change on GitHub + +### v2021.3.18 (13 mar 2021) +- Replace ``TorrentStates.FORCE_DOWNLOAD='forceDL'`` with ``TorrentStates.FORCED_DOWNLOAD='forcedDL'`` + +### v2021.2.17 (7 feb 2021) +- Generally refactor ``requests.py`` so it's better and easier to read +- Persist a Requests Session between API calls instead of always creating a new one...small perf benefit +- Move auth endpoints back to a dedicated module +- Since ``attrdict`` is apparently going to break in Python 3.10 and it is no longer maintained, I've vendored a modified version (fixes #45). +- Created ``handle_hashes`` decorator to hide the cruft of continuing to support hash and hashes arguments + +### v2021.1.16 (26 jan 2021) +- Support qBittorrent v4.3.3 and Web API v2.7 (...again) +- New ``torrents/renameFile`` and ``torrents/renameFolder`` endpoints +- Retrieve app api version when needed instead of caching +- Stop verifying and removing individual parameters when they aren't supported + +### v2020.12.15 (27 dec 2020) +- Support qBittorrent v4.3.2 and Web API v2.7 +- ``torrents/add`` supports adding torrents with tags via ``tags`` parameter +- ``app/preferences`` supports toggling internationalized domain name (IDN) support via ``idn_support_enabled`` +- BREAKING CHANGE: for ``torrents/add``, ``is_root_folder`` (or ``root_folder``) is superseded by ``content_layout`` +- For ``torrents/delete``, ``delete_files`` now defaults to ``False`` instead of required being explicitly passed + +### v2020.12.14 (6 dec 2020) +- Add support for non-standard API endpoint paths (Fixes #37) +- Allows users to leverage this client when qBittorrent is configured behind a reverse proxy. + - For instance, if the Web API is being exposed at "http://localhost/qbt/", then users can instantiate via ``Client(host='localhost/qbt')`` and all API endpoint paths will be prefixed with "/qbt". +- Additionally, the scheme (i.e. http or https) from the user will now be respected as the first choice for which scheme is used to communicate with qBittorrent. + - However, users still don't need to even specify a scheme; it'll be automatically determined on the first connection to qBittorrent. +- Neither of these should be breaking changes, but if you're instantiating with an incorrect scheme or an irrelevant path, you may need to prevent doing that now. + +### v2020.11.13 (29 nov 2020) +- Support qBittorrent v4.3.1 and Web API v2.6.1 +- Path of torrent content now available via ``content_path`` from ``torrents/info`` + +### v2020.11.12 (16 nov 2020) +- Fix support for raw bytes for ``torrent_files`` in ``torrents_add()`` for Python 3. Fixes #34. + +### v2020.10.11 (29 oct 2020) +- Support qBittorrent v4.3.0.1 and Web API v2.6 +- Due to qBittorrent changes, ``search/categories`` no longer returns anything and ``rss/renameRule`` works again + +### v2020.10.10 (7 oct 2020) +- Advertise support for Python 3.9 + +### v2020.9.9 (12 sept 2020) +- Only request ``enum34`` for Python 2 + +### v2020.8.8 (14 aug 2020) +- Support adding torrents from raw torrent files as bytes or file handles. Fixes #23. +- Introduce ``TorrentStates`` enum for qBittorrent list of torrent states. + +### v2020.7.7 (26 jul 2020) +- Update tests and misc small fixes. + +### v2020.7.6 (25 jul 2020) +- Re-release of v2020.7.5. + +### v2020.7.5 (25 jul 2020) +- Add RTD documentation. + +### v2020.6.4 (9 jun 2020) +- Bug fix release. Reorganized code and classes to be more logical. +- Started returning None from many methods that were returning Requests Responses. +- Content-Length header is now explicitly sent as "0" for any POSTs without a body. +- Endpoint input parameters ``hash`` and ``hashes`` are renamed to ``torrent_hash`` and ``torrent_hashes``. ``hash`` and ``hashes`` remain supported. +- ``search_uninstall_plugin`` now works. search_enable_plugin now supports multiple plugins. +- ``Torrent.download_limit`` now only return the value instead of a dictionary. ``Torrent.upload_limit`` now works. +- Drop advertising Python 2.6 and 3.4 support; add PyPy3 support. +- Implement test suite and CI that can test all supported qBittorrent versions on all pythons. + +### v2020.5.3 (11 may 2020) +- Include currently supported qBittorrent version in README. Fixes #11. + +### v2020.4.2 (25 apr 2020) +- Add support for ``rss/markAsRead`` and ``rss/matchingArticles``. Added in v2.5.1. Fixes #10 + +### v2020.4.1 (25 apr 2020) +- Add ``stalled()``, ``stalled_uploading()``, and ``stalled_downloading()`` to ``torrents.info`` interaction. Added in Web API v2.4.1. +- Implement torrent file renaming. Added in Web API v2.4.0. Fixes #3. +- Since versioning was botched last release, implement calendar versioning. +- List of files returned from ``torrents_files()`` now contains file ID in ``id``. + +### v6.0.0 (22 apr 2020) +- Performance gains for responses with payloads...especially for large payloads. +- Fixes #6. Adds support for ``SIMPLE_RESPONSES`` for the entire client and individual methods. + +### v0.5.2 (19 apr 2020) +- Fixes #8. Remove whitespace from in setPreferences requests for older qBittorrent versions. + +### v0.5.1 (2 jan 2020) +- Add Python3.8 version for PyPI +- Move project from beta to stable for PyPI + +### v0.5.0 (2 jan 2020) +- Make Web API URL derivation more robust...thereby allowing the client to actually work on Python3.8 (#5) +- Allow port to be discretely specified during Client instantiation (#4) +- Enhance request retry logic and expose retry configuration + +### v0.4.2 (5 dec 2019) +- Improve organization and clarity of README +- Better document exceptions +- Clarify torrent file handling exceptions better with proper exceptions +- Clean up the request wrapper exception handling +- Fix HTTP 404 handling to find and return problematic torrent hashes + +### v0.4.1 (4 dec 2019) +- Round out support for tags with qBittorrent v4.2.0 release +- Remove upper-bound version requirements for ``requests`` and ``urllib3`` + +### v0.4 (4 dec 2019) +- Support for qBittorrent v4.2.0 release +- Add support for ``app/buildInfo`` +- Add support for ``transfer/banPeers`` and ``torrents/addPeers`` +- Add support for ``torrents/addTags``, ``torrents/removeTags``, ``torrents/tags``, ``torrents/createTags``, and ``torrents/deleteTags`` + +### v0.3.3 (29 sept 2019) +- Fix useAutoTMM to autoTMM for ``client.torrents_add()`` so auto torrent management works +- Add support to refresh RSS items introduced in qBittorrent v4.1.8 + +### v0.3.2 (28 jun 2019) +- Restore python 2 compatibility +- Allow exceptions to be imported directly from package instead of only exceptions module + +### v0.3 (1 jun 2019) +- Finalized interaction layer interfaces + +### v0.2 (13 may 2019) +- Introduced the "interaction layer" for transparent interaction with the qBittorrent API. + +### v0.1 (7 may 2019) +- Complete implementation of qBittorrent WebUI API 2.2. +- Each API endpoint is available via the ``Client`` class. +- Automatic re-login is supported in the event of login expiration. diff --git a/CHANGELOG.txt b/CHANGELOG.txt deleted file mode 100644 index 451712874..000000000 --- a/CHANGELOG.txt +++ /dev/null @@ -1,209 +0,0 @@ -Version 2022.8.38 (31 aug 2022) - - Advertise support for qBittorrent v4.4.5 - -Version 2022.8.37 (24 aug 2022) - - Advertise support for qBittorrent v4.4.4 - -Version 2022.8.36 (15 aug 2022) - - Comply with enforced HTTP method requirements from qBittorrent - -Version 2022.8.35 (13 aug 2022) - - Remove PYTHON_ prefix for configuration environment variables - -Version 2022.8.34 (11 aug 2022) - - Add setuptools as an explicit dependency for pkg_resources.parse_version - -Version 2022.7.33 (27 jul 2022) - - Reorder class hierarchy to allow independent MixIn use - - Clean up typing annotations - - Optimize Dictionary and List initializations - - Rename Alias decorator to alias for better conformity - -Version 2022.5.32 (30 may 2022) - - Implement pre-commit checks - - Advertise support for qBittorrent 4.4.3.1 - -Version 2022.5.31 (24 may 2022) - - Advertise support for qBittorrent 4.4.3 - - Revamp Github CI - - Reorg Request for some more clarity (hopefully) - -Version 2022.4.30 (3 apr 2022) - - Stop advertising support for Python 3.6 (EOL 12/2021) - - Publish to PyPI using API token and cleanup GitHub Action scripts - -Version 2022.3.29 (25 mar 2022) - - Advertise support for qBittorrent v4.4.2 - -Version 2022.2.28 (17 feb 2022) - - Advertise support for qBittorrent v4.4.1 - - qBittorrent reverted the category dictionary key "savePath" back to "save_path" - -Version 2022.1.27 (9 jan 2022) - - Support for qBittorrent v4.4.0 - - torrents/info results can now be filtered by a torrent tag - - Added new torrent state "Forced Metadata Downloading" - - Support per-torrent/per-category "download folder" - -Version 2021.12.26 (11 dec 2021) - - Stop sending Origin and Referer headers (Fixes #63) - -Version 2021.12.25 (10 dec 2021) - - Close files that are opened and sent to Requests when adding torrents from files - - Enable warnings for tests and explicitly close Requests Sessions to prevent (mostly spurious) ResourceWarnings - -Version 2021.12.24 (3 dec 2021) - - Add Type Hints for all public and private functions, methods, and variables - - Support HTTP timeouts as well as arbitrary Requests configurations - -Version 2021.8.23 (28 aug 2021) - - Advertise support for qBittorrent 4.3.8 - - Drop support for Python 3.5 - -Version 2021.5.22 (12 may 2021) - - Support for qBittorrent v4.3.5 - - torrents/files includes "index" for each file; "index" officially replaces "id" but "id" will still be populated - -Version 2021.5.21 (1 may 2021) - - Allow users to force a specific communications scheme with FORCE_SCHEME_FROM_HOST (fixes #54) - -Version 2021.4.20 (11 apr 2021) - - Add support for ratio limit and seeding time limit when adding torrents - -Version 2021.4.19 (8 apr 2021) - - Update license in setup to match gpl->mit license change on github - -Version 2021.3.18 (13 mar 2021) - - Replace TorrentStates.FORCE_DOWNLOAD='forceDL' with TorrentStates.FORCED_DOWNLOAD='forcedDL' - -Version 2021.2.17 (7 feb 2021) - - Generally refactor requests.py so it's better and easier to read - - Persist a Requests Session between API calls instead of always creating a new one...small perf benefit - - Move auth endpoints back to a dedicated module - - Since attrdict is apparently going to break in Python 3.10 and it is no longer maintained, i've vendored a modified version (fixes #45). - - Created handle_hashes decorator to hide the cruft of continuing to support hash and hashes arguments - -Version 2021.1.16 (26 jan 2021) - - Support qBittorrent v4.3.3 and Web API v2.7 (...again) - - New torrents/renameFile and torrents/renameFolder endpoints - - Retrieve app api version when needed instead of caching - - Stop verifying and removing individual parameters when they aren't supported - -Version 2020.12.15 (27 dec 2020) - - Support qBittorrent v4.3.2 and Web API v2.7 - - torrents/add supports adding torrents with tags via "tags" parameter - - app/preferences supports toggling internationalized domain name (IDN) support via "idn_support_enabled" - - BREAKING CHANGE: for torrents/add, "is_root_folder" (or "root_folder") is superseded by "content_layout" - - For torrents/delete, "delete_files" now defaults to False instead of required being explicitly passed - -Version 2020.12.14 (6 dec 2020) - - Add support for non-standard API endpoint paths (Fixes #37) - - Allows users to leverage this client when qBittorrent is configured behind a reverse proxy. - - For instance, if the Web API is being exposed at "http://localhost/qbt/", then users can instantiate via Client(host='localhost/qbt') and all API endpoint paths will be prefixed with "/qbt". - - Additionally, the scheme (i.e. http or https) from the user will now be respected as the first choice for which scheme is used to communicate with qBittorrent. - - However, users still don't need to even specify a scheme; it'll be automatically determined on the first connection to qBittorrent. - - Neither of these should be breaking changes, but if you're instantiating with an incorrect scheme or an irrelevant path, you may need to prevent doing that now. - -Version 2020.11.13 (29 nov 2020) - - Support qBittorrent v4.3.1 and Web API v2.6.1 - - Path of torrent content now available via content_path from torrents/info - -Version 2020.11.12 (16 nov 2020) - - Fix support for raw bytes for torrent_files in torrents_add() for Python 3. Fixes #34. - -Version 2020.10.11 (29 oct 2020) - - Support qBittorrent v4.3.0.1 and Web API v2.6 - - Due to qBittorrent changes, /search/categories no longer returns anything and /rss/renameRule works again - -Version 2020.10.10 (7 oct 2020) - - Advertise support for Python 3.9 - -Version 2020.9.9 (12 sept 2020) - - Only request enum34 for Python 2 - -Version 2020.8.8 (14 aug 2020) - - Support adding torrents from raw torrent files as bytes or file handles. Fixes #23. - - Introduce TorrentStates enum for qBittorrent list of torrent states. - -Version 2020.7.7 (26 jul 2020) - - Update tests and misc small fixes. - -Version 2020.7.6 (25 jul 2020) - - Re-release of v2020.7.5. - -Version 2020.7.5 (25 jul 2020) - - Add RTD documentation. - -Version 2020.6.4 (9 jun 2020) - - Bug fix release. Reorganized code and classes to be more logical. - - Started returning None from many methods that were returning Requests Responses. - - Content-Length header is now explicitly sent as "0" for any POSTs without a body. - - Endpoint input parameters "hash" and "hashes" are renamed to "torrent_hash" and "torrent_hashes". "hash" and "hashes" remain supported. - - search_uninstall_plugin now works. search_enable_plugin now supports multiple plugins. - - Torrent.download_limit now only return the value instead of a dictionary. Torrent.upload_limit now works. - - Drop advertising Python 2.6 and 3.4 support; add PyPy3 support. - - Implement test suite and CI that can test all supported qBittorrent versions on all pythons. - -Version 2020.5.3 (11 may 2020) - - Include currently supported qBittorrent version in README. Fixes #11. - -Version 2020.4.2 (25 apr 2020) - - Add support for rss/markAsRead and rss/matchingArticles. Added in v2.5.1. Fixes #10 - -Version 2020.4.1 (25 apr 2020) - - Add stalled(), stalled_uploading(), and stalled_downloading() to torrents.info interaction. Added in Web API v2.4.1. - - Implement torrent file renaming. Added in Web API v2.4.0. Fixes #3. - - Since versioning was botched last release, implement calendar versioning. - - List of files returned from torrents_files() now contains file ID in 'id'. - -Version 6.0.0 (22 apr 2020) - - Performance gains for responses with payloads...especially for large payloads. - - Fixes #6. Adds support for SIMPLE_RESPONSES for the entire client and individual methods. - -Version 0.5.2 (19 apr 2020) - - Fixes #8. Remove whitespace from in setPreferences requests for older qBittorrent versions. - -Version 0.5.1 (2 jan 2020) - - Add Python3.8 version for PyPI - - Move project from beta to stable for PyPI - -Version 0.5.0 (2 jan 2020) - - Make Web API URL derivation more robust...thereby allowing the client to actually work on Python3.8 (#5) - - Allow port to be discretely specified during Client instantiation (#4) - - Enhance request retry logic and expose retry configuration - -Version 0.4.2 (5 dec 2019) - - Improve organization and clarity of README - - Better document exceptions - - Clarify torrent file handling exceptions better with proper exceptions - - Clean up the request wrapper exception handling - - Fix HTTP 404 handling to find and return problematic torrent hashes - -Version 0.4.1 (4 dec 2019) - - Round out support for tags with qBittorrent v4.2.0 release - - Remove upper-bound version requirements for requests and urllib3 - -Version 0.4 (4 dec 2019) - - Support for qBittorrent v4.2.0 release - - Add support for app/buildInfo - - Add support for transfer/banPeers and torrents/addPeers - - Add support for torrents/addTags, torrents/removeTags, torrents/tags, torrents/createTags, and torrents/deleteTags - -Version 0.3.3 (29 sept 2019) - - Fix useAutoTMM to autoTMM for client.torrents_add() so auto torrent management works - - Add support to refresh RSS items introduced in qBittorrent v4.1.8 - -Version 0.3.2 (28 jun 2019) - - Restore python 2 compatibility - - Allow exceptions to be imported directly from package instead of only exceptions module - -Version 0.3 (1 jun 2019) - - Finalized interaction layer interfaces - -Version 0.2 (13 may 2019) - - Introduced the "interaction layer" for transparent interaction with the qBittorrent API. - -Version 0.1 (7 may 2019) - - Complete implementation of qBittorrent WebUI API 2.2. - - Each API endpoint is available via the Client class. - - Automatic re-login is supported in the event of login expiration. diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index 4ec9518fa..000000000 --- a/MANIFEST.in +++ /dev/null @@ -1,5 +0,0 @@ -include CHANGELOG.txt -include LICENSE -include README.md - -global-exclude *.py[cod] __pycache__ *.so diff --git a/pyproject.toml b/pyproject.toml index 16f9e0bdc..7a8b8c051 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,5 +12,42 @@ multi_line_output = 3 target-version = ['py34'] include = '\.pyi?$' -[tool.pytest] -testpaths = "tests" +[tool.pytest.ini_options] +testpaths = ["tests"] +norecursedirs = "dist build .tox scripts" +filterwarnings = ["error"] +addopts = """ + --doctest-modules + --cov=qbittorrentapi + --cov-report=xml + --cov-report=html + --no-cov-on-fail + -r a + -v +""" + +[tool.coverage.run] +branch = true +source = ["qbittorrentapi"] +omit = ["qbittorrentapi/_attrdict.py"] + +[tool.coverage.report] +show_missing = true +skip_covered = true +exclude_lines = [ + # search categories was deprecated + "class SearchCategoriesList", + "def search_categories", + # defaults to exclude + "pragma: no cover", + "def __repr__", + "if self.debug:", + "if settings.DEBUG", + "raise AssertionError", + "raise NotImplementedError", + "if 0:", + "if __name__ == .__main__.:", +] + +[tool.coverage.html] +skip_empty = true diff --git a/pytest.ini b/pytest.ini deleted file mode 100644 index 73bf946ed..000000000 --- a/pytest.ini +++ /dev/null @@ -1,13 +0,0 @@ -[pytest] -testpaths = tests -norecursedirs = dist build .tox scripts -filterwarnings = - error -addopts = - --doctest-modules - --cov=qbittorrentapi - --cov-report=xml - --cov-report=html - --no-cov-on-fail - -r a - -v diff --git a/qbittorrentapi/_version_support.py b/qbittorrentapi/_version_support.py index cc518f47d..9af7d770a 100644 --- a/qbittorrentapi/_version_support.py +++ b/qbittorrentapi/_version_support.py @@ -2,7 +2,7 @@ try: from functools import lru_cache -except ImportError: +except ImportError: # pragma: no cover from backports.functools_lru_cache import lru_cache diff --git a/qbittorrentapi/definitions.py b/qbittorrentapi/definitions.py index 5c6000cb9..a0e39ccb8 100644 --- a/qbittorrentapi/definitions.py +++ b/qbittorrentapi/definitions.py @@ -2,7 +2,7 @@ try: from collections import UserList -except ImportError: +except ImportError: # pragma: no cover from UserList import UserList from qbittorrentapi._attrdict import AttrDict diff --git a/qbittorrentapi/request.py b/qbittorrentapi/request.py index 5607280cc..31b5c4292 100644 --- a/qbittorrentapi/request.py +++ b/qbittorrentapi/request.py @@ -8,7 +8,7 @@ from collections.abc import Iterable from urllib.parse import urljoin from urllib.parse import urlparse -except ImportError: # python 2 +except ImportError: # python 2 # pragma: no cover from collections import Iterable from urlparse import urljoin from urlparse import urlparse diff --git a/qbittorrentapi/torrents.py b/qbittorrentapi/torrents.py index 4546d65ca..8403d7700 100644 --- a/qbittorrentapi/torrents.py +++ b/qbittorrentapi/torrents.py @@ -6,7 +6,7 @@ try: from collections.abc import Iterable from collections.abc import Mapping -except ImportError: +except ImportError: # pragma: no cover from collections import Iterable from collections import Mapping @@ -1254,9 +1254,9 @@ def _normalize_torrent_files(user_files): # this does prevent providing more useful IO errors on python 2....but it's dead anyway... try: filepath = path.abspath( - path.realpath(path.expanduser(str(torrent_file))) + path.realpath(path.expanduser(torrent_file.decode())) ) - if path.exists(filepath): + if path.exists(filepath): # pragma: no branch fh = open(filepath, "rb") files_to_close.append(fh) name = path.basename(filepath) diff --git a/requirements-dev.txt b/requirements-dev.txt deleted file mode 100644 index b73ef79db..000000000 --- a/requirements-dev.txt +++ /dev/null @@ -1,13 +0,0 @@ --r requirements.txt -black -build -codecov -coveralls -flake8 -furo -mock; python_version < "3" -pre-commit -pytest -pytest-cov -sphinx -sphinx-copybutton diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index e208e6432..000000000 --- a/requirements.txt +++ /dev/null @@ -1,5 +0,0 @@ -enum34; python_version < "3" -requests >= 2.16.0 -setuptools -six -urllib3 >= 1.24.2 diff --git a/setup.cfg b/setup.cfg index 18c7cd3e5..0dea05685 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = qbittorrent-api -version = 2022.8.38 +version = 2022.10.39 author = Russell Martin author_email = rmartin16@gmail.com maintainer = Russell Martin @@ -11,6 +11,7 @@ project_urls = API Reference = https://qbittorrent-api.readthedocs.io/en/latest/api.html Source = https://github.com/rmartin16/qbittorrent-api classifiers = + Programming Language :: Python :: 3.11 Programming Language :: Python :: 3.10 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.8 @@ -30,7 +31,7 @@ classifiers = license = MIT license_files = LICENSE description = Python client for qBittorrent v4.1+ Web API. -long_description = file: README.md +long_description = file: README.md, CHANGELOG.md, LICENSE long_description_content_type = text/markdown; charset=UTF-8 keywords = python @@ -46,7 +47,6 @@ platforms = any [options] zip_safe = False packages = find: -include_package_data = True install_requires = enum34; python_version < "3" requests >= 2.16.0 @@ -59,6 +59,7 @@ install_requires = test = build codecov + coverage[toml] coveralls mock; python_version < "3" pytest diff --git a/tests/test_torrents.py b/tests/test_torrents.py index 32fcf91bd..163ad7bb4 100644 --- a/tests/test_torrents.py +++ b/tests/test_torrents.py @@ -115,7 +115,9 @@ def inner(**kwargs): def add_by_filename(single): download_file(url=torrent1_url, filename=torrent1_filename) download_file(url=torrent2_url, filename=torrent2_filename) - files = ("~/%s" % torrent1_filename, "~/%s" % torrent2_filename) + # send bytes as a proxy for testing python 2 + kw = {} if version_info.major == 2 else dict(encoding="utf-8") + files = ("~/%s" % torrent1_filename, bytes("~/%s" % torrent2_filename, **kw)) if single: assert get_func(client, client_func[0])(torrent_files=files[0]) == "Ok."