From 519acedf46acc9c132a3d7b3498c9afaaf9f67b9 Mon Sep 17 00:00:00 2001 From: Jakub Kuczys Date: Fri, 30 Dec 2022 03:21:57 +0100 Subject: [PATCH] Make some dependency changes, support Python 3.10 and 3.11 (#5611) Co-authored-by: jack1142 <6032823+jack1142@users.noreply.github.com> --- .github/workflows/tests.yml | 14 ++- docs/cog_guides/customcommands.rst | 2 +- docs/conf.py | 6 +- ...nv.rst => _create-env-with-venv-intro.rst} | 15 --- .../_includes/_create-env-with-venv-outro.rst | 10 ++ .../_includes/create-env-with-venv3.10.rst | 7 ++ .../_includes/create-env-with-venv3.11.rst | 7 ++ .../_includes/create-env-with-venv3.9.rst | 7 ++ .../install-guide-rhel8-derivatives.rst | 4 +- .../install-guide-rhel9-derivatives.rst | 4 +- .../_includes/install-python-pyenv.rst | 8 +- .../_includes/install-python310-pyenv.rst | 27 ++++++ ...8-pyenv.rst => install-python39-pyenv.rst} | 8 +- docs/install_guides/arch.rst | 16 +++- docs/install_guides/centos-7.rst | 4 +- docs/install_guides/debian-10.rst | 2 +- docs/install_guides/debian-11.rst | 4 +- docs/install_guides/fedora.rst | 4 +- docs/install_guides/mac.rst | 6 +- docs/install_guides/opensuse-leap-15.rst | 8 +- docs/install_guides/opensuse-tumbleweed.rst | 4 +- docs/install_guides/raspberry-pi-os-10.rst | 9 +- docs/install_guides/raspberry-pi-os-11.rst | 4 +- docs/install_guides/ubuntu-1804.rst | 10 +- docs/install_guides/ubuntu-2004.rst | 14 +-- docs/install_guides/ubuntu-2204.rst | 14 +-- docs/install_guides/ubuntu-non-lts.rst | 17 +--- docs/install_guides/windows.rst | 6 +- docs/version_guarantees.rst | 1 - pyproject.toml | 7 +- redbot/__init__.py | 20 +++- .../cogs/audio/core/utilities/local_tracks.py | 4 +- redbot/cogs/audio/core/utilities/queue.py | 16 ++-- redbot/cogs/customcom/customcom.py | 10 +- redbot/core/bot.py | 2 + redbot/core/data_manager.py | 22 +++-- redbot/core/rpc.py | 13 ++- redbot/core/utils/_internal_utils.py | 12 +-- redbot/logging.py | 13 ++- redbot/pytest/rpc.py | 6 +- requirements/base.in | 15 +-- requirements/base.txt | 92 +++++++++++-------- requirements/extra-doc.txt | 22 ++--- requirements/extra-postgres.txt | 2 +- requirements/extra-style.txt | 10 +- requirements/extra-test.txt | 30 +++--- setup.py | 4 +- tests/cogs/downloader/test_downloader.py | 18 ---- tests/cogs/downloader/test_git.py | 37 -------- tests/cogs/test_alias.py | 6 -- tests/cogs/test_economy.py | 8 -- tests/cogs/test_mod.py | 3 - tests/core/test_cog_manager.py | 6 -- tests/core/test_config.py | 58 ------------ tests/core/test_installation.py | 1 - tests/core/test_utils.py | 3 - tests/core/test_version.py | 2 +- tools/dev-requirements.txt | 2 +- tox.ini | 11 ++- 59 files changed, 324 insertions(+), 373 deletions(-) rename docs/install_guides/_includes/{create-env-with-venv.rst => _create-env-with-venv-intro.rst} (71%) create mode 100644 docs/install_guides/_includes/_create-env-with-venv-outro.rst create mode 100644 docs/install_guides/_includes/create-env-with-venv3.10.rst create mode 100644 docs/install_guides/_includes/create-env-with-venv3.11.rst create mode 100644 docs/install_guides/_includes/create-env-with-venv3.9.rst create mode 100644 docs/install_guides/_includes/install-python310-pyenv.rst rename docs/install_guides/_includes/{install-python38-pyenv.rst => install-python39-pyenv.rst} (83%) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 4783b8b7c..3ce731928 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -27,8 +27,11 @@ jobs: python_version: "3.9" friendly_name: Python 3.9 - Tests - tox_env: py310 - python_version: "3.10-dev" - friendly_name: Python 3.10-dev - Tests + python_version: "3.10" + friendly_name: Python 3.10 - Tests + - tox_env: py311 + python_version: "3.11" + friendly_name: Python 3.11 - Tests - tox_env: style friendly_name: Style - tox_env: docs @@ -46,7 +49,7 @@ jobs: - name: Install tox run: | python -m pip install --upgrade pip - pip install 'tox<4' + pip install tox - name: Tox test env: TOXENV: ${{ matrix.tox_env }} @@ -59,7 +62,8 @@ jobs: python_version: - "3.8" - "3.9" - - "3.10-dev" + - "3.10" + - "3.11" fail-fast: false name: Tox - Postgres services: @@ -82,7 +86,7 @@ jobs: - name: Install tox run: | python -m pip install --upgrade pip - pip install 'tox<4' + pip install tox - name: Tox test env: TOXENV: postgres diff --git a/docs/cog_guides/customcommands.rst b/docs/cog_guides/customcommands.rst index c6ba97944..e79526f5b 100644 --- a/docs/cog_guides/customcommands.rst +++ b/docs/cog_guides/customcommands.rst @@ -267,7 +267,7 @@ customcom search Searches through custom commands, according to the query. -Uses fuzzywuzzy searching to find close matches. +Uses fuzzy searching to find close matches. **Arguments:** diff --git a/docs/conf.py b/docs/conf.py index 73eec3ea4..a99240fae 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -82,7 +82,7 @@ release = __version__ # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. -language = None +language = "en" # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. @@ -246,8 +246,8 @@ intersphinx_mapping = { # :dpy_docs:`link text ` extlinks = { "dpy_docs": (f"{dpy_docs_url}/%s", None), - "issue": ("https://github.com/Cog-Creators/Red-DiscordBot/issues/%s", "#"), - "ghuser": ("https://github.com/%s", "@"), + "issue": ("https://github.com/Cog-Creators/Red-DiscordBot/issues/%s", "#%s"), + "ghuser": ("https://github.com/%s", "@%s"), } # Doctest diff --git a/docs/install_guides/_includes/create-env-with-venv.rst b/docs/install_guides/_includes/_create-env-with-venv-intro.rst similarity index 71% rename from docs/install_guides/_includes/create-env-with-venv.rst rename to docs/install_guides/_includes/_create-env-with-venv-intro.rst index b51ba8b4b..dde85481a 100644 --- a/docs/install_guides/_includes/create-env-with-venv.rst +++ b/docs/install_guides/_includes/_create-env-with-venv-intro.rst @@ -21,18 +21,3 @@ to keep it in a location which is easy to type out the path to. From now, we'll ``redenv`` and it will be located in your home directory. Create your virtual environment with the following command: - -.. prompt:: bash - - python3.9 -m venv ~/redenv - -And activate it with the following command: - -.. prompt:: bash - - source ~/redenv/bin/activate - -.. important:: - - You must activate the virtual environment with the above command every time you open a new - shell to run, install or update Red. diff --git a/docs/install_guides/_includes/_create-env-with-venv-outro.rst b/docs/install_guides/_includes/_create-env-with-venv-outro.rst new file mode 100644 index 000000000..e3b9eca4b --- /dev/null +++ b/docs/install_guides/_includes/_create-env-with-venv-outro.rst @@ -0,0 +1,10 @@ +And activate it with the following command: + +.. prompt:: bash + + source ~/redenv/bin/activate + +.. important:: + + You must activate the virtual environment with the above command every time you open a new + shell to run, install or update Red. diff --git a/docs/install_guides/_includes/create-env-with-venv3.10.rst b/docs/install_guides/_includes/create-env-with-venv3.10.rst new file mode 100644 index 000000000..af858034c --- /dev/null +++ b/docs/install_guides/_includes/create-env-with-venv3.10.rst @@ -0,0 +1,7 @@ +.. include:: _includes/_create-env-with-venv-intro.rst + +.. prompt:: bash + + python3.10 -m venv ~/redenv + +.. include:: _includes/_create-env-with-venv-outro.rst diff --git a/docs/install_guides/_includes/create-env-with-venv3.11.rst b/docs/install_guides/_includes/create-env-with-venv3.11.rst new file mode 100644 index 000000000..1f77150d4 --- /dev/null +++ b/docs/install_guides/_includes/create-env-with-venv3.11.rst @@ -0,0 +1,7 @@ +.. include:: _includes/_create-env-with-venv-intro.rst + +.. prompt:: bash + + python3.11 -m venv ~/redenv + +.. include:: _includes/_create-env-with-venv-outro.rst diff --git a/docs/install_guides/_includes/create-env-with-venv3.9.rst b/docs/install_guides/_includes/create-env-with-venv3.9.rst new file mode 100644 index 000000000..b2aed2869 --- /dev/null +++ b/docs/install_guides/_includes/create-env-with-venv3.9.rst @@ -0,0 +1,7 @@ +.. include:: _includes/_create-env-with-venv-intro.rst + +.. prompt:: bash + + python3.9 -m venv ~/redenv + +.. include:: _includes/_create-env-with-venv-outro.rst diff --git a/docs/install_guides/_includes/install-guide-rhel8-derivatives.rst b/docs/install_guides/_includes/install-guide-rhel8-derivatives.rst index 8f64ce014..7052a25db 100644 --- a/docs/install_guides/_includes/install-guide-rhel8-derivatives.rst +++ b/docs/install_guides/_includes/install-guide-rhel8-derivatives.rst @@ -13,7 +13,7 @@ Install them with dnf: sudo dnf -y update sudo dnf -y group install development - sudo dnf -y install python39 python39-pip python39-devel java-11-openjdk-headless nano git + sudo dnf -y install python39 python39-devel java-11-openjdk-headless nano git Set ``java`` executable to point to Java 11: @@ -23,6 +23,6 @@ Set ``java`` executable to point to Java 11: .. Include common instructions: -.. include:: _includes/create-env-with-venv.rst +.. include:: _includes/create-env-with-venv3.9.rst .. include:: _includes/install-and-setup-red-unix.rst diff --git a/docs/install_guides/_includes/install-guide-rhel9-derivatives.rst b/docs/install_guides/_includes/install-guide-rhel9-derivatives.rst index 83dd9c52b..9e149cc56 100644 --- a/docs/install_guides/_includes/install-guide-rhel9-derivatives.rst +++ b/docs/install_guides/_includes/install-guide-rhel9-derivatives.rst @@ -11,10 +11,10 @@ Install them with dnf: .. prompt:: bash - sudo dnf -y install python39 git java-11-openjdk-headless @development nano + sudo dnf -y install python39 python3-devel git java-11-openjdk-headless @development nano .. Include common instructions: -.. include:: _includes/create-env-with-venv.rst +.. include:: _includes/create-env-with-venv3.9.rst .. include:: _includes/install-and-setup-red-unix.rst diff --git a/docs/install_guides/_includes/install-python-pyenv.rst b/docs/install_guides/_includes/install-python-pyenv.rst index 438ca33ba..ff6f88ecc 100644 --- a/docs/install_guides/_includes/install-python-pyenv.rst +++ b/docs/install_guides/_includes/install-python-pyenv.rst @@ -2,7 +2,7 @@ Installing Python with pyenv ---------------------------- -On distributions where Python 3.9 needs to be compiled from source, we recommend the use of pyenv. +On distributions where Python 3.11 needs to be compiled from source, we recommend the use of pyenv. This simplifies the compilation process and has the added bonus of simplifying setting up Red in a virtual environment. @@ -10,7 +10,7 @@ virtual environment. .. prompt:: bash - CONFIGURE_OPTS=--enable-optimizations pyenv install 3.9.9 -v + CONFIGURE_OPTS=--enable-optimizations pyenv install 3.11.1 -v This may take a long time to complete, depending on your hardware. For some machines (such as Raspberry Pis and micro-tier VPSes), it may take over an hour; in this case, you may wish to remove @@ -22,6 +22,6 @@ After that is finished, run: .. prompt:: bash - pyenv global 3.9.9 + pyenv global 3.11.1 -Pyenv is now installed and your system should be configured to run Python 3.9. +Pyenv is now installed and your system should be configured to run Python 3.11. diff --git a/docs/install_guides/_includes/install-python310-pyenv.rst b/docs/install_guides/_includes/install-python310-pyenv.rst new file mode 100644 index 000000000..c60409292 --- /dev/null +++ b/docs/install_guides/_includes/install-python310-pyenv.rst @@ -0,0 +1,27 @@ +---------------------------- +Installing Python with pyenv +---------------------------- + +On distributions where Python 3.10 needs to be compiled from source, we recommend the use of pyenv. +This simplifies the compilation process and has the added bonus of simplifying setting up Red in a +virtual environment. + +.. include:: _includes/_install-pyenv-and-setup-path.rst + +.. prompt:: bash + + CONFIGURE_OPTS=--enable-optimizations pyenv install 3.10.9 -v + +This may take a long time to complete, depending on your hardware. For some machines (such as +Raspberry Pis and micro-tier VPSes), it may take over an hour; in this case, you may wish to remove +the ``CONFIGURE_OPTS=--enable-optimizations`` part from the front of the command, which will +drastically reduce the install time. However, be aware that this will make Python run about 10% +slower. + +After that is finished, run: + +.. prompt:: bash + + pyenv global 3.10.9 + +Pyenv is now installed and your system should be configured to run Python 3.10. diff --git a/docs/install_guides/_includes/install-python38-pyenv.rst b/docs/install_guides/_includes/install-python39-pyenv.rst similarity index 83% rename from docs/install_guides/_includes/install-python38-pyenv.rst rename to docs/install_guides/_includes/install-python39-pyenv.rst index f48314868..ce312eb08 100644 --- a/docs/install_guides/_includes/install-python38-pyenv.rst +++ b/docs/install_guides/_includes/install-python39-pyenv.rst @@ -2,7 +2,7 @@ Installing Python with pyenv ---------------------------- -On distributions where Python 3.8 needs to be compiled from source, we recommend the use of pyenv. +On distributions where Python 3.9 needs to be compiled from source, we recommend the use of pyenv. This simplifies the compilation process and has the added bonus of simplifying setting up Red in a virtual environment. @@ -10,7 +10,7 @@ virtual environment. .. prompt:: bash - CONFIGURE_OPTS=--enable-optimizations pyenv install 3.8.12 -v + CONFIGURE_OPTS=--enable-optimizations pyenv install 3.9.16 -v This may take a long time to complete, depending on your hardware. For some machines (such as Raspberry Pis and micro-tier VPSes), it may take over an hour; in this case, you may wish to remove @@ -22,6 +22,6 @@ After that is finished, run: .. prompt:: bash - pyenv global 3.8.12 + pyenv global 3.9.16 -Pyenv is now installed and your system should be configured to run Python 3.8. +Pyenv is now installed and your system should be configured to run Python 3.9. diff --git a/docs/install_guides/arch.rst b/docs/install_guides/arch.rst index f69adf257..0b472fb4a 100644 --- a/docs/install_guides/arch.rst +++ b/docs/install_guides/arch.rst @@ -16,10 +16,22 @@ Install the pre-requirements with pacman: .. prompt:: bash - sudo pacman -Syu python python-pip git jre11-openjdk-headless base-devel nano + sudo pacman -Syu git jre11-openjdk-headless base-devel nano + +On Arch Linux, Python 3.9 can be installed from the Arch User Repository (AUR) from the ``python39`` package. + +The manual build process is the Arch-supported install method for AUR packages. You can install ``python39`` package with the following commands: + +.. prompt:: bash + + git clone https://aur.archlinux.org/python39.git /tmp/python39 + cd /tmp/python39 + makepkg -sicL + cd - + rm -rf /tmp/python39 .. Include common instructions: -.. include:: _includes/create-env-with-venv.rst +.. include:: _includes/create-env-with-venv3.9.rst .. include:: _includes/install-and-setup-red-unix.rst diff --git a/docs/install_guides/centos-7.rst b/docs/install_guides/centos-7.rst index bdce4faf9..f49e59dca 100644 --- a/docs/install_guides/centos-7.rst +++ b/docs/install_guides/centos-7.rst @@ -37,7 +37,9 @@ In order to install Git 2.11 or greater, we recommend adding the IUS repository: .. Include common instructions: -.. include:: _includes/install-python-pyenv.rst +.. Python 3.10 requires OpenSSL 1.1.1 which CentOS 7 doesn't provide in base repository. + +.. include:: _includes/install-python39-pyenv.rst .. include:: _includes/create-env-with-pyenv-virtualenv.rst diff --git a/docs/install_guides/debian-10.rst b/docs/install_guides/debian-10.rst index d71d105c9..47ee4e28d 100644 --- a/docs/install_guides/debian-10.rst +++ b/docs/install_guides/debian-10.rst @@ -18,7 +18,7 @@ Debian Buster. This guide will tell you how. First, run the following commands: .. prompt:: bash sudo apt update - sudo apt -y install make build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev libgdbm-dev uuid-dev python3-openssl git openjdk-11-jre-headless nano + sudo apt -y install make build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev libgdbm-dev uuid-dev python3-openssl git openjdk-11-jre-headless nano CXX=/usr/bin/g++ .. Include common instructions: diff --git a/docs/install_guides/debian-11.rst b/docs/install_guides/debian-11.rst index 19488943a..4ea9bd014 100644 --- a/docs/install_guides/debian-11.rst +++ b/docs/install_guides/debian-11.rst @@ -18,10 +18,10 @@ with apt: .. prompt:: bash sudo apt update - sudo apt -y install python3 python3-dev python3-venv python3-pip git openjdk-11-jre-headless build-essential nano + sudo apt -y install python3 python3-dev python3-venv git openjdk-11-jre-headless build-essential nano .. Include common instructions: -.. include:: _includes/create-env-with-venv.rst +.. include:: _includes/create-env-with-venv3.9.rst .. include:: _includes/install-and-setup-red-unix.rst diff --git a/docs/install_guides/fedora.rst b/docs/install_guides/fedora.rst index 9492b72cd..79de09f68 100644 --- a/docs/install_guides/fedora.rst +++ b/docs/install_guides/fedora.rst @@ -17,10 +17,10 @@ them with dnf: .. prompt:: bash - sudo dnf -y install python39 git java-11-openjdk-headless @development-tools nano + sudo dnf -y install python3.10 python3.10-devel git java-11-openjdk-headless @development-tools nano .. Include common instructions: -.. include:: _includes/create-env-with-venv.rst +.. include:: _includes/create-env-with-venv3.10.rst .. include:: _includes/install-and-setup-red-unix.rst diff --git a/docs/install_guides/mac.rst b/docs/install_guides/mac.rst index e2127f61c..b3c44e32f 100644 --- a/docs/install_guides/mac.rst +++ b/docs/install_guides/mac.rst @@ -23,7 +23,7 @@ one-by-one: .. prompt:: bash - brew install python@3.9 + brew install python@3.11 brew install git brew tap homebrew/cask-versions brew install --cask temurin11 @@ -34,11 +34,11 @@ To fix this, you should run these commands: .. prompt:: bash profile=$([ -n "$ZSH_VERSION" ] && echo ~/.zprofile || ([ -f ~/.bash_profile ] && echo ~/.bash_profile || echo ~/.profile)) - echo 'export PATH="$(brew --prefix)/opt/python@3.9/bin:$PATH"' >> "$profile" + echo 'export PATH="$(brew --prefix)/opt/python@3.11/bin:$PATH"' >> "$profile" source "$profile" .. Include common instructions: -.. include:: _includes/create-env-with-venv.rst +.. include:: _includes/create-env-with-venv3.11.rst .. include:: _includes/install-and-setup-red-unix.rst diff --git a/docs/install_guides/opensuse-leap-15.rst b/docs/install_guides/opensuse-leap-15.rst index a6e9be37e..e5f24d692 100644 --- a/docs/install_guides/opensuse-leap-15.rst +++ b/docs/install_guides/opensuse-leap-15.rst @@ -1,7 +1,7 @@ .. _install-opensuse-leap-15: ===================================== -Installing Red on openSUSE Leap 15.3+ +Installing Red on openSUSE Leap 15.4+ ===================================== .. include:: _includes/supported-arch-x64+aarch64.rst @@ -12,16 +12,16 @@ Installing Red on openSUSE Leap 15.3+ Installing the pre-requirements ------------------------------- -openSUSE Leap 15.3+ has all required dependencies available in official repositories. Install them +openSUSE Leap 15.4+ has all required dependencies available in official repositories. Install them with zypper: .. prompt:: bash - sudo zypper -n install python39-base python39-pip git-core java-11-openjdk-headless nano + sudo zypper -n install python310 python310-devel git-core java-11-openjdk-headless nano sudo zypper -n install -t pattern devel_basis .. Include common instructions: -.. include:: _includes/create-env-with-venv.rst +.. include:: _includes/create-env-with-venv3.10.rst .. include:: _includes/install-and-setup-red-unix.rst diff --git a/docs/install_guides/opensuse-tumbleweed.rst b/docs/install_guides/opensuse-tumbleweed.rst index 588789360..047b5eaad 100644 --- a/docs/install_guides/opensuse-tumbleweed.rst +++ b/docs/install_guides/opensuse-tumbleweed.rst @@ -17,11 +17,11 @@ with zypper: .. prompt:: bash - sudo zypper -n install python39-base python39-pip git-core java-11-openjdk-headless nano + sudo zypper -n install python311 python311-devel git-core java-11-openjdk-headless nano sudo zypper -n install -t pattern devel_basis .. Include common instructions: -.. include:: _includes/create-env-with-venv.rst +.. include:: _includes/create-env-with-venv3.11.rst .. include:: _includes/install-and-setup-red-unix.rst diff --git a/docs/install_guides/raspberry-pi-os-10.rst b/docs/install_guides/raspberry-pi-os-10.rst index 5d28a4914..48bf582da 100644 --- a/docs/install_guides/raspberry-pi-os-10.rst +++ b/docs/install_guides/raspberry-pi-os-10.rst @@ -35,15 +35,20 @@ Installing the pre-requirements We recommend installing pyenv as a method of installing non-native versions of Python on Raspberry Pi OS. This guide will tell you how. First, run the following commands: +.. cmake is necessary to be able to successfuly build rapidfuzz. + .. prompt:: bash sudo apt update - sudo apt -y install make build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev libgdbm-dev uuid-dev python3-openssl git openjdk-11-jre-headless nano + sudo apt -y install cmake make build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev libgdbm-dev uuid-dev python3-openssl git openjdk-11-jre-headless nano CXX=/usr/bin/g++ .. Include common instructions: -.. include:: _includes/install-python38-pyenv.rst +.. We should only build and install even versions of Python on Raspberry Pi OS as odd +.. versions are part of piwheels and can cause installs of pip packages that won't work. + +.. include:: _includes/install-python310-pyenv.rst .. include:: _includes/create-env-with-pyenv-virtualenv.rst diff --git a/docs/install_guides/raspberry-pi-os-11.rst b/docs/install_guides/raspberry-pi-os-11.rst index 1882d2eb6..5e8eeead5 100644 --- a/docs/install_guides/raspberry-pi-os-11.rst +++ b/docs/install_guides/raspberry-pi-os-11.rst @@ -33,10 +33,10 @@ with apt: .. prompt:: bash sudo apt update - sudo apt -y install python3 python3-dev python3-venv python3-pip git openjdk-11-jre-headless build-essential nano + sudo apt -y install python3 python3-dev python3-venv git openjdk-11-jre-headless build-essential nano .. Include common instructions: -.. include:: _includes/create-env-with-venv.rst +.. include:: _includes/create-env-with-venv3.9.rst .. include:: _includes/install-and-setup-red-unix.rst diff --git a/docs/install_guides/ubuntu-1804.rst b/docs/install_guides/ubuntu-1804.rst index 9cd4d6016..a967fb533 100644 --- a/docs/install_guides/ubuntu-1804.rst +++ b/docs/install_guides/ubuntu-1804.rst @@ -12,6 +12,10 @@ Installing Red on Ubuntu 18.04 LTS Installing the pre-requirements ------------------------------- +.. Git 2.17.0-2.22.0 have an issue with partial clone which is used in pip for git installs. +.. Not incredibly important perhaps but this ppa is recommended by git-scm.com/download/linux +.. so it should be fine. + We recommend adding the ``git-core`` ppa to install Git 2.11 or greater: .. prompt:: bash @@ -20,7 +24,7 @@ We recommend adding the ``git-core`` ppa to install Git 2.11 or greater: sudo apt -y install software-properties-common sudo add-apt-repository -y ppa:git-core/ppa -We recommend adding the ``deadsnakes`` ppa to install Python 3.9: +We recommend adding the ``deadsnakes`` ppa to install Python 3.11: .. prompt:: bash @@ -30,10 +34,10 @@ Now install the pre-requirements with apt: .. prompt:: bash - sudo apt -y install python3.9 python3.9-dev python3.9-venv python3-pip git openjdk-11-jre-headless build-essential nano + sudo apt -y install python3.11 python3.11-dev python3.11-venv git openjdk-11-jre-headless build-essential nano .. Include common instructions: -.. include:: _includes/create-env-with-venv.rst +.. include:: _includes/create-env-with-venv3.11.rst .. include:: _includes/install-and-setup-red-unix.rst diff --git a/docs/install_guides/ubuntu-2004.rst b/docs/install_guides/ubuntu-2004.rst index 074973e61..0ad76922a 100644 --- a/docs/install_guides/ubuntu-2004.rst +++ b/docs/install_guides/ubuntu-2004.rst @@ -12,22 +12,16 @@ Installing Red on Ubuntu 20.04 LTS Installing the pre-requirements ------------------------------- -We recommend adding the ``git-core`` ppa to install Git 2.11 or greater: +Ubuntu 20.04 LTS has all required packages available in official repositories. Install them +with apt: .. prompt:: bash sudo apt update - sudo apt -y install software-properties-common - sudo add-apt-repository -y ppa:git-core/ppa - -Now install the pre-requirements with apt: - -.. prompt:: bash - - sudo apt -y install python3.9 python3.9-dev python3.9-venv python3-pip git openjdk-11-jre-headless build-essential nano + sudo apt -y install python3.9 python3.9-dev python3.9-venv git openjdk-11-jre-headless build-essential nano .. Include common instructions: -.. include:: _includes/create-env-with-venv.rst +.. include:: _includes/create-env-with-venv3.9.rst .. include:: _includes/install-and-setup-red-unix.rst diff --git a/docs/install_guides/ubuntu-2204.rst b/docs/install_guides/ubuntu-2204.rst index 74e68372e..50df7c0ad 100644 --- a/docs/install_guides/ubuntu-2204.rst +++ b/docs/install_guides/ubuntu-2204.rst @@ -12,22 +12,16 @@ Installing Red on Ubuntu 22.04 LTS Installing the pre-requirements ------------------------------- -We recommend adding the ``deadsnakes`` ppa to install Python 3.9: +Ubuntu 22.04 LTS has all required packages available in official repositories. Install them +with apt: .. prompt:: bash sudo apt update - sudo apt -y install software-properties-common - sudo add-apt-repository -y ppa:deadsnakes/ppa - -Now install the pre-requirements with apt: - -.. prompt:: bash - - sudo apt -y install python3.9 python3.9-dev python3.9-venv python3-pip git openjdk-11-jre-headless build-essential nano + sudo apt -y install python3.10 python3.10-dev python3.10-venv git openjdk-11-jre-headless build-essential nano .. Include common instructions: -.. include:: _includes/create-env-with-venv.rst +.. include:: _includes/create-env-with-venv3.10.rst .. include:: _includes/install-and-setup-red-unix.rst diff --git a/docs/install_guides/ubuntu-non-lts.rst b/docs/install_guides/ubuntu-non-lts.rst index b12365279..b2db202af 100644 --- a/docs/install_guides/ubuntu-non-lts.rst +++ b/docs/install_guides/ubuntu-non-lts.rst @@ -12,26 +12,15 @@ Installing Red on Ubuntu non-LTS versions Installing the pre-requirements ------------------------------- -We recommend adding the ``git-core`` ppa to install Git 2.11 or greater: +Now install the pre-requirements with apt: .. prompt:: bash sudo apt update - sudo apt -y install software-properties-common - sudo add-apt-repository -yu ppa:git-core/ppa - -Now, to install non-native version of python on non-LTS versions of Ubuntu, we recommend -installing pyenv. To do this, first run the following commands: - -.. prompt:: bash - - sudo apt -y install make build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev libgdbm-dev uuid-dev python3-openssl git openjdk-11-jre-headless nano - CXX=/usr/bin/g++ + sudo apt -y install python3.11 python3.11-dev python3.11-venv git openjdk-11-jre-headless build-essential nano .. Include common instructions: -.. include:: _includes/install-python-pyenv.rst - -.. include:: _includes/create-env-with-pyenv-virtualenv.rst +.. include:: _includes/create-env-with-venv3.11.rst .. include:: _includes/install-and-setup-red-unix.rst diff --git a/docs/install_guides/windows.rst b/docs/install_guides/windows.rst index 5584154d0..de3ed7866 100644 --- a/docs/install_guides/windows.rst +++ b/docs/install_guides/windows.rst @@ -33,7 +33,7 @@ Then run each of the following commands: iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1')) choco upgrade git --params "/GitOnlyOnPath /WindowsTerminal" -y choco upgrade visualstudio2022-workload-vctools -y - choco upgrade python3 -y --version 3.9.9 + choco upgrade python311 -y For Audio support, you should also run the following command before exiting: @@ -57,7 +57,7 @@ Manually installing dependencies * `MSVC Build tools `_ -* `Python 3.8.1 - 3.9.x `_ +* `Python 3.8.1 - 3.11.x `_ .. attention:: Please make sure that the box to add Python to PATH is CHECKED, otherwise you may run into issues when trying to run Red. @@ -104,7 +104,7 @@ Then create your virtual environment with the following command .. prompt:: batch - py -3.9 -m venv "%userprofile%\redenv" + py -3.11 -m venv "%userprofile%\redenv" And activate it with the following command diff --git a/docs/version_guarantees.rst b/docs/version_guarantees.rst index 2ad9f1dfe..758a32f11 100644 --- a/docs/version_guarantees.rst +++ b/docs/version_guarantees.rst @@ -64,7 +64,6 @@ Debian 10 Buster x86-64, aarch64, armv7l 2022-08-14 (`End of Debian 11 Bullseye x86-64, aarch64, armv7l ~2024-09 (`End of life `__) Fedora Linux 35 x86-64, aarch64 2022-11-15 (`End of Life `__) Fedora Linux 36 x86-64, aarch64 2023-05-16 (`End of Life `__) -openSUSE Leap 15.3 x86-64, aarch64 2022-11-30 (`end of maintenance life cycle `__) openSUSE Leap 15.4 x86-64, aarch64 2023-11-30 (`end of maintenance life cycle `__) openSUSE Tumbleweed x86-64, aarch64 forever (support is only provided for an up-to-date system) Oracle Linux 8 x86-64, aarch64 2029-07-31 (`End of Premier Support `__) diff --git a/pyproject.toml b/pyproject.toml index 08529574e..fa005b9e2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,6 +20,8 @@ classifiers = [ "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", "Topic :: Communications :: Chat", ] dynamic = ["version", "requires-python", "dependencies", "optional-dependencies"] @@ -42,7 +44,7 @@ red-discordbot = "redbot.pytest" [tool.black] line-length = 99 -required-version = '22.1.0' +required-version = '22' target-version = ['py38'] include = '\.py$' force-exclude = ''' @@ -50,3 +52,6 @@ force-exclude = ''' redbot\/vendored )/ ''' + +[tool.pytest.ini_options] +asyncio_mode = 'auto' diff --git a/redbot/__init__.py b/redbot/__init__.py index caed5eddd..967459d06 100644 --- a/redbot/__init__.py +++ b/redbot/__init__.py @@ -269,8 +269,12 @@ def _ensure_no_colorama(): from rich.console import detect_legacy_windows if not detect_legacy_windows(): - import colorama - import colorama.initialise + try: + import colorama + import colorama.initialise + except ModuleNotFoundError: + # colorama is not Red's primary dependency so it might not be present + return colorama.deinit() @@ -300,8 +304,6 @@ _VERSION = "3.5.0.dev1" __version__, version_info = VersionInfo._get_version() -# Filter fuzzywuzzy slow sequence matcher warning -_warnings.filterwarnings("ignore", module=r"fuzzywuzzy.*") # Show DeprecationWarning _warnings.filterwarnings("default", category=DeprecationWarning) @@ -320,3 +322,13 @@ if not any(_re.match("^-(-debug|d+|-verbose|v+)$", i) for i in _sys.argv): module="asyncio", message="The loop argument is deprecated since Python 3.8", ) + # DEP-WARN - d.py currently uses audioop module, Danny is aware of the deprecation + # + # DeprecationWarning: 'audioop' is deprecated and slated for removal in Python 3.13 + # import audioop + _warnings.filterwarnings( + "ignore", + category=DeprecationWarning, + module="discord", + message="'audioop' is deprecated and slated for removal", + ) diff --git a/redbot/cogs/audio/core/utilities/local_tracks.py b/redbot/cogs/audio/core/utilities/local_tracks.py index f4a42bae2..ed33f2157 100644 --- a/redbot/cogs/audio/core/utilities/local_tracks.py +++ b/redbot/cogs/audio/core/utilities/local_tracks.py @@ -7,7 +7,7 @@ import discord import lavalink from red_commons.logging import getLogger -from fuzzywuzzy import process +from rapidfuzz import process from redbot.core import commands from redbot.core.i18n import Translator from redbot.core.utils import AsyncIter @@ -118,7 +118,7 @@ class LocalTrackUtilities(MixinMeta, metaclass=CompositeMetaClass): } search_results = process.extract(search_words, to_search_string, limit=50) search_list = [] - async for track_match, percent_match in AsyncIter(search_results): + async for track_match, percent_match, __ in AsyncIter(search_results): if percent_match > 85: search_list.extend( [ diff --git a/redbot/cogs/audio/core/utilities/queue.py b/redbot/cogs/audio/core/utilities/queue.py index 0024a56b0..d6d8c3a8b 100644 --- a/redbot/cogs/audio/core/utilities/queue.py +++ b/redbot/cogs/audio/core/utilities/queue.py @@ -7,7 +7,7 @@ import discord import lavalink from red_commons.logging import getLogger -from fuzzywuzzy import process +from rapidfuzz import process from redbot.core import commands from redbot.core.i18n import Translator from redbot.core.utils import AsyncIter @@ -116,7 +116,7 @@ class QueueUtilities(MixinMeta, metaclass=CompositeMetaClass): async def _build_queue_search_list( self, queue_list: List[lavalink.Track], search_words: str ) -> List[Tuple[int, str]]: - track_list = [] + tracks = {} async for queue_idx, track in AsyncIter(queue_list).enumerate(start=1): if not self.match_url(track.uri): query = Query.process_input(track, self.local_folder_current_path) @@ -131,14 +131,12 @@ class QueueUtilities(MixinMeta, metaclass=CompositeMetaClass): else: track_title = track.title - song_info = {str(queue_idx): track_title} - track_list.append(song_info) - search_results = process.extract(search_words, track_list, limit=50) + tracks[queue_idx] = track_title + search_results = process.extract(search_words, tracks, limit=50) search_list = [] - async for search, percent_match in AsyncIter(search_results): - async for queue_position, title in AsyncIter(search.items()): - if percent_match > 89: - search_list.append((queue_position, title)) + async for title, percent_match, queue_position in AsyncIter(search_results): + if percent_match > 89: + search_list.append((queue_position, title)) return search_list async def _build_queue_search_page( diff --git a/redbot/cogs/customcom/customcom.py b/redbot/cogs/customcom/customcom.py index 6865075a5..659e45ed9 100644 --- a/redbot/cogs/customcom/customcom.py +++ b/redbot/cogs/customcom/customcom.py @@ -7,7 +7,7 @@ from typing import Iterable, List, Mapping, Tuple, Dict, Set, Literal, Union from urllib.parse import quote_plus import discord -from fuzzywuzzy import process +from rapidfuzz import process from redbot.core import Config, checks, commands from redbot.core.i18n import Translator, cog_i18n @@ -317,7 +317,7 @@ class CustomCommands(commands.Cog): """ Searches through custom commands, according to the query. - Uses fuzzywuzzy searching to find close matches. + Uses fuzzy searching to find close matches. **Arguments:** @@ -326,10 +326,10 @@ class CustomCommands(commands.Cog): cc_commands = await CommandObj.get_commands(self.config.guild(ctx.guild)) extracted = process.extract(query, list(cc_commands.keys())) accepted = [] - for entry in extracted: - if entry[1] > 60: + for key, score, __ in extracted: + if score > 60: # Match was decently strong - accepted.append((entry[0], cc_commands[entry[0]])) + accepted.append((key, cc_commands[key])) else: # Match wasn't strong enough pass diff --git a/redbot/core/bot.py b/redbot/core/bot.py index a055d9617..7e58375c0 100644 --- a/redbot/core/bot.py +++ b/redbot/core/bot.py @@ -1098,6 +1098,8 @@ class Red( """ This should only be run once, prior to logging in to Discord REST API. """ + await super()._pre_login() + await self._maybe_update_config() self.description = await self._config.description() self._color = discord.Colour(await self._config.color()) diff --git a/redbot/core/data_manager.py b/redbot/core/data_manager.py index 762a99a71..85169ad86 100644 --- a/redbot/core/data_manager.py +++ b/redbot/core/data_manager.py @@ -8,7 +8,7 @@ from copy import deepcopy from pathlib import Path from typing import Any, Dict -import appdirs +import platformdirs from discord.utils import deprecated from . import commands @@ -37,22 +37,30 @@ basic_config_default: Dict[str, Any] = { "CORE_PATH_APPEND": "core", } -appdir = appdirs.AppDirs("Red-DiscordBot") -config_dir = Path(appdir.user_config_dir) +appdir = platformdirs.PlatformDirs("Red-DiscordBot") +config_dir = appdir.user_config_path _system_user = sys.platform == "linux" and 0 < os.getuid() < 1000 if _system_user: if Path.home().exists(): # We don't want to break someone just because they created home dir - # but were already using the site_data_dir. + # but were already using the site_data_path. # - # But otherwise, we do want Red to use user_config_dir if home dir exists. - _maybe_config_file = Path(appdir.site_data_dir) / "config.json" + # But otherwise, we do want Red to use user_config_path if home dir exists. + _maybe_config_file = appdir.site_data_path / "config.json" if _maybe_config_file.exists(): config_dir = _maybe_config_file.parent else: - config_dir = Path(appdir.site_data_dir) + config_dir = appdir.site_data_path config_file = config_dir / "config.json" +if not config_file.exists() and sys.platform == "darwin": + # backwards compatibility with the location given by appdirs 1.4.4 (replaced by platformdirs 2) + # which was the same as user_data_path + # https://platformdirs.readthedocs.io/en/stable/changelog.html#platformdirs-2-0-0 + _old_config_location = appdir.user_data_path / "config.json" + if _old_config_location.exists(): + config_dir.mkdir(parents=True, exist_ok=True) + _old_config_location.rename(config_file) def load_existing_config(): diff --git a/redbot/core/rpc.py b/redbot/core/rpc.py index b2ee0eb4a..b5f0a9f1f 100644 --- a/redbot/core/rpc.py +++ b/redbot/core/rpc.py @@ -64,14 +64,20 @@ class RPC: RPC server manager. """ + app: web.Application + _rpc: RedRpc + _runner: web.AppRunner + def __init__(self): + self._site: Optional[web.TCPSite] = None + self._started = False + + async def _pre_login(self) -> None: self.app = web.Application() self._rpc = RedRpc() self.app.router.add_route("*", "/", self._rpc.handle_request) self._runner = web.AppRunner(self.app) - self._site: Optional[web.TCPSite] = None - self._started = False async def initialize(self, port: int): """ @@ -134,6 +140,9 @@ class RPCMixin: self.rpc_handlers = {} # Uppercase cog name to method + async def _pre_login(self) -> None: + await self.rpc._pre_login() + def register_rpc_handler(self, method): """ Registers a method to act as an RPC handler if the internal RPC server is active. diff --git a/redbot/core/utils/_internal_utils.py b/redbot/core/utils/_internal_utils.py index 8407fdedf..5ea383549 100644 --- a/redbot/core/utils/_internal_utils.py +++ b/redbot/core/utils/_internal_utils.py @@ -32,7 +32,7 @@ from typing import ( import aiohttp import discord from packaging.requirements import Requirement -from fuzzywuzzy import fuzz, process +from rapidfuzz import fuzz, process from rich.progress import ProgressColumn from rich.progress_bar import ProgressBar from red_commons.logging import VERBOSE, TRACE @@ -147,20 +147,20 @@ async def fuzzy_command_search( return None if commands is None: - choices = set(ctx.bot.walk_commands()) + choices = {c: c.qualified_name for c in ctx.bot.walk_commands()} elif isinstance(commands, collections.abc.AsyncIterator): - choices = {c async for c in commands} + choices = {c: c.qualified_name async for c in commands} else: - choices = set(commands) + choices = {c: c.qualified_name for c in commands} - # Do the scoring. `extracted` is a list of tuples in the form `(command, score)` + # Do the scoring. `extracted` is a list of tuples in the form `(cmd_name, score, cmd)` extracted = process.extract(term, choices, limit=5, scorer=fuzz.QRatio) if not extracted: return None # Filter through the fuzzy-matched commands. matched_commands = [] - for command, score in extracted: + for __, score, command in extracted: if score < min_score: # Since the list is in decreasing order of score, we can exit early. break diff --git a/redbot/logging.py b/redbot/logging.py index 5b5ef5991..0e21793e5 100644 --- a/redbot/logging.py +++ b/redbot/logging.py @@ -10,7 +10,7 @@ from datetime import datetime # This clearly never leads to confusion... from os import isatty import rich -from pygments.styles.monokai import MonokaiStyle +from pygments.styles.monokai import MonokaiStyle # DEP-WARN from pygments.token import ( Comment, Error, @@ -22,16 +22,14 @@ from pygments.token import ( Token, ) from rich._log_render import LogRender # DEP-WARN -from rich.console import render_group -from rich.containers import Renderables +from rich.console import group from rich.highlighter import NullHighlighter from rich.logging import RichHandler from rich.style import Style -from rich.syntax import ANSISyntaxTheme, PygmentsSyntaxTheme -from rich.table import Table +from rich.syntax import ANSISyntaxTheme, PygmentsSyntaxTheme # DEP-WARN from rich.text import Text from rich.theme import Theme -from rich.traceback import PathHighlighter, Traceback +from rich.traceback import PathHighlighter, Traceback # DEP-WARN MAX_OLD_LOGS = 8 @@ -151,7 +149,8 @@ class FixedMonokaiStyle(MonokaiStyle): class RedTraceback(Traceback): - @render_group() + # DEP-WARN + @group() def _render_stack(self, stack): for obj in super()._render_stack.__wrapped__(self, stack): if obj != "": diff --git a/redbot/pytest/rpc.py b/redbot/pytest/rpc.py index 5ad7900da..ffe3029d7 100644 --- a/redbot/pytest/rpc.py +++ b/redbot/pytest/rpc.py @@ -7,8 +7,10 @@ __all__ = ["rpc", "rpcmixin", "cog", "existing_func", "existing_multi_func"] @pytest.fixture() -def rpc(): - return RPC() +async def rpc(): + rpc = RPC() + await rpc._pre_login() + return rpc @pytest.fixture() diff --git a/requirements/base.in b/requirements/base.in index 53bb09b0e..ca4f650f7 100644 --- a/requirements/base.in +++ b/requirements/base.in @@ -1,23 +1,24 @@ +aiodns aiohttp aiohttp-json-rpc -aiosqlite -appdirs -apsw-wheels +apsw babel +Brotli click -colorama discord.py -fuzzywuzzy markdown +orjson packaging +platformdirs psutil python-dateutil -python-Levenshtein-wheels -PyNaCl PyYAML +rapidfuzz Red-Commons Red-Lavalink>=0.11.0rc1 rich schema +typing_extensions +yarl distro; sys_platform == "linux" uvloop; sys_platform != "win32" and platform_python_implementation == "CPython" diff --git a/requirements/base.txt b/requirements/base.txt index e69fa803b..4e707a83e 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -1,4 +1,6 @@ -aiohttp==3.7.4.post0 +aiodns==3.0.0 + # via -r base.in +aiohttp==3.8.3 # via # -r base.in # aiohttp-json-rpc @@ -6,28 +8,24 @@ aiohttp==3.7.4.post0 # red-lavalink aiohttp-json-rpc==0.13.3 # via -r base.in -aiosqlite==0.17.0 - # via -r base.in -appdirs==1.4.4 - # via -r base.in -apsw-wheels==3.36.0.post1 - # via -r base.in -async-timeout==3.0.1 +aiosignal==1.3.1 # via aiohttp -attrs==21.2.0 - # via aiohttp -babel==2.9.1 +apsw==3.40.0.0 # via -r base.in -cffi==1.14.6 - # via pynacl -chardet==4.0.0 +async-timeout==4.0.2 # via aiohttp -click==8.0.1 +attrs==22.2.0 + # via aiohttp +babel==2.11.0 + # via -r base.in +brotli==1.0.9 + # via -r base.in +cffi==1.15.1 + # via pycares +charset-normalizer==2.1.1 + # via aiohttp +click==8.1.3 # via -r base.in -colorama==0.4.4 - # via - # -r base.in - # click commonmark==0.9.1 # via rich contextlib2==21.6.0 @@ -36,33 +34,41 @@ discord-py==2.1.0 # via # -r base.in # red-lavalink -fuzzywuzzy==0.18.0 - # via -r base.in -idna==3.2 +frozenlist==1.3.3 + # via + # aiohttp + # aiosignal +idna==3.4 # via yarl -markdown==3.3.4 +importlib-metadata==5.2.0 + # via markdown +markdown==3.4.1 # via -r base.in -multidict==5.1.0 +multidict==6.0.4 # via # aiohttp # yarl +orjson==3.8.3 + # via -r base.in packaging==22.0 # via -r base.in -psutil==5.8.0 +platformdirs==2.6.0 # via -r base.in -pycparser==2.20 +psutil==5.9.4 + # via -r base.in +pycares==4.3.0 + # via aiodns +pycparser==2.21 # via cffi -pygments==2.10.0 +pygments==2.13.0 # via rich -pynacl==1.4.0 - # via -r base.in python-dateutil==2.8.2 # via -r base.in -python-levenshtein-wheels==0.13.2 - # via -r base.in -pytz==2021.1 +pytz==2022.7 # via babel -pyyaml==5.4.1 +pyyaml==6.0 + # via -r base.in +rapidfuzz==2.13.7 # via -r base.in red-commons==1.0.0 # via @@ -70,19 +76,25 @@ red-commons==1.0.0 # red-lavalink red-lavalink==0.11.0rc1 # via -r base.in -rich==10.9.0 +rich==12.6.0 # via -r base.in -schema==0.7.4 +schema==0.7.5 # via -r base.in six==1.16.0 # via python-dateutil -typing-extensions==3.10.0.2 - # via rich -yarl==1.6.3 +typing-extensions==4.4.0 + # via + # -r base.in + # rich +yarl==1.8.2 # via # -r base.in # aiohttp -distro==1.6.0; sys_platform == "linux" +zipp==3.11.0 + # via importlib-metadata +colorama==0.4.6; sys_platform == "win32" + # via click +distro==1.8.0; sys_platform == "linux" and sys_platform == "linux" # via -r base.in -uvloop==0.16.0; sys_platform != "win32" and platform_python_implementation == "CPython" +uvloop==0.17.0; (sys_platform != "win32" and platform_python_implementation == "CPython") and sys_platform != "win32" # via -r base.in diff --git a/requirements/extra-doc.txt b/requirements/extra-doc.txt index eed9cb2e3..b38c9ab94 100644 --- a/requirements/extra-doc.txt +++ b/requirements/extra-doc.txt @@ -1,24 +1,22 @@ alabaster==0.7.12 # via sphinx -certifi==2021.5.30 +certifi==2022.12.7 # via requests -charset-normalizer==2.0.4 - # via requests -docutils==0.16 +docutils==0.17.1 # via # sphinx # sphinx-rtd-theme -imagesize==1.2.0 +imagesize==1.4.1 # via sphinx -jinja2==3.0.1 +jinja2==3.1.2 # via sphinx -markupsafe==2.0.1 +markupsafe==2.1.1 # via jinja2 -requests==2.26.0 +requests==2.28.1 # via sphinx -snowballstemmer==2.1.0 +snowballstemmer==2.2.0 # via sphinx -sphinx==4.1.2 +sphinx==5.3.0 # via # -r extra-doc.in # sphinx-prompt @@ -26,7 +24,7 @@ sphinx==4.1.2 # sphinxcontrib-trio sphinx-prompt==1.5.0 # via -r extra-doc.in -sphinx-rtd-theme==0.5.2 +sphinx-rtd-theme==1.1.1 # via -r extra-doc.in sphinxcontrib-applehelp==1.0.2 # via sphinx @@ -42,5 +40,5 @@ sphinxcontrib-serializinghtml==1.1.5 # via sphinx sphinxcontrib-trio==1.1.2 # via -r extra-doc.in -urllib3==1.26.6 +urllib3==1.26.13 # via requests diff --git a/requirements/extra-postgres.txt b/requirements/extra-postgres.txt index 945c075af..35809367b 100644 --- a/requirements/extra-postgres.txt +++ b/requirements/extra-postgres.txt @@ -1,2 +1,2 @@ -asyncpg==0.24.0 +asyncpg==0.27.0 # via -r extra-postgres.in diff --git a/requirements/extra-style.txt b/requirements/extra-style.txt index dde309b4d..4d70be2e8 100644 --- a/requirements/extra-style.txt +++ b/requirements/extra-style.txt @@ -1,12 +1,8 @@ -black==22.1.0 +black==22.12.0 # via -r extra-style.in mypy-extensions==0.4.3 # via black -pathspec==0.9.0 +pathspec==0.10.3 # via black -regex==2021.8.28 - # via black -toml==0.10.2 - # via black -typed-ast==1.4.3 +tomli==2.0.1 # via black diff --git a/requirements/extra-test.txt b/requirements/extra-test.txt index ea453cbf3..770190d81 100644 --- a/requirements/extra-test.txt +++ b/requirements/extra-test.txt @@ -1,33 +1,35 @@ -astroid==2.7.3 +astroid==2.12.13 # via pylint +dill==0.3.6 + # via pylint +exceptiongroup==1.1.0 + # via pytest iniconfig==1.1.1 # via pytest -isort==5.9.3 +isort==5.11.4 # via pylint -lazy-object-proxy==1.6.0 +lazy-object-proxy==1.8.0 # via astroid -mccabe==0.6.1 - # via pylint -platformdirs==2.3.0 +mccabe==0.7.0 # via pylint pluggy==1.0.0 # via pytest -py==1.10.0 - # via pytest -pylint==2.10.2 +pylint==2.15.9 # via -r extra-test.in -pytest==6.2.5 +pytest==7.2.0 # via # -r extra-test.in # pytest-asyncio # pytest-mock -pytest-asyncio==0.15.1 +pytest-asyncio==0.20.3 # via -r extra-test.in -pytest-mock==3.6.1 +pytest-mock==3.10.0 # via -r extra-test.in -toml==0.10.2 +tomli==2.0.1 # via # pylint # pytest -wrapt==1.12.1 +tomlkit==0.11.6 + # via pylint +wrapt==1.14.1 # via astroid diff --git a/setup.py b/setup.py index 58d1b8f9f..3ecbf527d 100644 --- a/setup.py +++ b/setup.py @@ -47,8 +47,8 @@ extras_require["all"] = extras_combined("postgres") python_requires = ">=3.8.1" -if not os.getenv("TOX_RED", False) or sys.version_info < (3, 10): - python_requires += ",<3.10" +if not os.getenv("TOX_RED", False) or sys.version_info < (3, 12): + python_requires += ",<3.12" # Metadata and options defined in pyproject.toml setup( diff --git a/tests/cogs/downloader/test_downloader.py b/tests/cogs/downloader/test_downloader.py index 71e3b811c..e60d401f4 100644 --- a/tests/cogs/downloader/test_downloader.py +++ b/tests/cogs/downloader/test_downloader.py @@ -65,7 +65,6 @@ ancestor_rev = "c950fc05a540dd76b944719c2a3302da2e2f3090" descendant_rev = "fb99eb7d2d5bed514efc98fe6686b368f8425745" -@pytest.mark.asyncio @pytest.mark.parametrize( "maybe_ancestor_rev,descendant_rev,returncode,expected", [(ancestor_rev, descendant_rev, 0, True), (descendant_rev, ancestor_rev, 1, False)], @@ -86,7 +85,6 @@ async def test_is_ancestor(mocker, repo, maybe_ancestor_rev, descendant_rev, ret assert ret is expected -@pytest.mark.asyncio async def test_is_ancestor_object_raise(mocker, repo): m = _mock_run(mocker, repo, 128, b"", b"fatal: Not a valid object name invalid1") with pytest.raises(UnknownRevision): @@ -104,7 +102,6 @@ async def test_is_ancestor_object_raise(mocker, repo): ) -@pytest.mark.asyncio async def test_is_ancestor_commit_raise(mocker, repo): m = _mock_run( mocker, @@ -130,7 +127,6 @@ async def test_is_ancestor_commit_raise(mocker, repo): ) -@pytest.mark.asyncio async def test_get_file_update_statuses(mocker, repo): old_rev = "c950fc05a540dd76b944719c2a3302da2e2f3090" new_rev = "fb99eb7d2d5bed514efc98fe6686b368f8425745" @@ -160,7 +156,6 @@ async def test_get_file_update_statuses(mocker, repo): } -@pytest.mark.asyncio async def test_is_module_modified(mocker, repo): old_rev = "c950fc05a540dd76b944719c2a3302da2e2f3090" new_rev = "fb99eb7d2d5bed514efc98fe6686b368f8425745" @@ -184,7 +179,6 @@ async def test_is_module_modified(mocker, repo): assert ret is True -@pytest.mark.asyncio async def test_get_full_sha1_success(mocker, repo): commit = "c950fc05a540dd76b944719c2a3302da2e2f3090" m = _mock_run(mocker, repo, 0, commit.encode()) @@ -196,7 +190,6 @@ async def test_get_full_sha1_success(mocker, repo): assert ret == commit -@pytest.mark.asyncio async def test_get_full_sha1_notfound(mocker, repo): m = _mock_run(mocker, repo, 128, b"", b"fatal: Needed a single revision") with pytest.raises(UnknownRevision): @@ -206,7 +199,6 @@ async def test_get_full_sha1_notfound(mocker, repo): ) -@pytest.mark.asyncio async def test_get_full_sha1_ambiguous(mocker, repo): m = _mock_run( mocker, @@ -246,7 +238,6 @@ def test_update_available_modules(repo): ) -@pytest.mark.asyncio async def test_checkout(mocker, repo): commit = "c950fc05a540dd76b944719c2a3302da2e2f3090" m = _mock_run(mocker, repo, 0) @@ -261,7 +252,6 @@ async def test_checkout(mocker, repo): ) -@pytest.mark.asyncio async def test_checkout_ctx_manager(mocker, repo): commit = "c950fc05a540dd76b944719c2a3302da2e2f3090" m = mocker.patch.object(repo, "_checkout", autospec=True, return_value=None) @@ -273,7 +263,6 @@ async def test_checkout_ctx_manager(mocker, repo): m.assert_called_with(old_commit, force_checkout=False) -@pytest.mark.asyncio async def test_checkout_await(mocker, repo): commit = "c950fc05a540dd76b944719c2a3302da2e2f3090" m = mocker.patch.object(repo, "_checkout", autospec=True, return_value=None) @@ -282,7 +271,6 @@ async def test_checkout_await(mocker, repo): m.assert_called_once_with(commit, force_checkout=False) -@pytest.mark.asyncio async def test_clone_with_branch(mocker, repo): branch = repo.branch = "dont_add_commits" commit = "a0ccc2390883c85a361f5a90c72e1b07958939fa" @@ -300,7 +288,6 @@ async def test_clone_with_branch(mocker, repo): ) -@pytest.mark.asyncio async def test_clone_without_branch(mocker, repo): branch = "dont_add_commits" commit = "a0ccc2390883c85a361f5a90c72e1b07958939fa" @@ -318,7 +305,6 @@ async def test_clone_without_branch(mocker, repo): ) -@pytest.mark.asyncio async def test_update(mocker, repo): old_commit = repo.commit new_commit = "a0ccc2390883c85a361f5a90c72e1b07958939fa" @@ -335,7 +321,6 @@ async def test_update(mocker, repo): # old tests -@pytest.mark.asyncio async def test_add_repo(monkeypatch, repo_manager): monkeypatch.setattr("redbot.cogs.downloader.repo_manager.Repo._run", fake_run_noprint) monkeypatch.setattr( @@ -349,7 +334,6 @@ async def test_add_repo(monkeypatch, repo_manager): assert squid.available_modules == () -@pytest.mark.asyncio async def test_lib_install_requirements(monkeypatch, library_installable, repo, tmpdir): monkeypatch.setattr("redbot.cogs.downloader.repo_manager.Repo._run", fake_run_noprint) monkeypatch.setattr( @@ -368,7 +352,6 @@ async def test_lib_install_requirements(monkeypatch, library_installable, repo, assert len(failed) == 0 -@pytest.mark.asyncio async def test_remove_repo(monkeypatch, repo_manager): monkeypatch.setattr("redbot.cogs.downloader.repo_manager.Repo._run", fake_run_noprint) monkeypatch.setattr( @@ -383,7 +366,6 @@ async def test_remove_repo(monkeypatch, repo_manager): assert repo_manager.get_repo("squid") is None -@pytest.mark.asyncio async def test_existing_repo(mocker, repo_manager): repo_manager.does_repo_exist = mocker.MagicMock(return_value=True) diff --git a/tests/cogs/downloader/test_git.py b/tests/cogs/downloader/test_git.py index e1cc1d517..a2e99734f 100644 --- a/tests/cogs/downloader/test_git.py +++ b/tests/cogs/downloader/test_git.py @@ -13,7 +13,6 @@ from redbot.pytest.downloader import ( ) -@pytest.mark.asyncio async def test_git_clone_nobranch(git_repo, tmp_path): p = await git_repo._run( ProcessFormatter().format( @@ -25,7 +24,6 @@ async def test_git_clone_nobranch(git_repo, tmp_path): assert p.returncode == 0 -@pytest.mark.asyncio async def test_git_clone_branch(git_repo, tmp_path): p = await git_repo._run( ProcessFormatter().format( @@ -38,7 +36,6 @@ async def test_git_clone_branch(git_repo, tmp_path): assert p.returncode == 0 -@pytest.mark.asyncio async def test_git_clone_non_existent_branch(git_repo, tmp_path): p = await git_repo._run( ProcessFormatter().format( @@ -51,7 +48,6 @@ async def test_git_clone_non_existent_branch(git_repo, tmp_path): assert p.returncode == 128 -@pytest.mark.asyncio async def test_git_clone_notgit_repo(git_repo, tmp_path): notgit_repo = tmp_path / "test_clone_folder" p = await git_repo._run( @@ -62,7 +58,6 @@ async def test_git_clone_notgit_repo(git_repo, tmp_path): assert p.returncode == 128 -@pytest.mark.asyncio async def test_git_current_branch_master(git_repo): p = await git_repo._run( ProcessFormatter().format(git_repo.GIT_CURRENT_BRANCH, path=git_repo.folder_path) @@ -71,7 +66,6 @@ async def test_git_current_branch_master(git_repo): assert p.stdout.decode().strip() == "master" -@pytest.mark.asyncio async def test_git_current_branch_detached(git_repo): await git_repo._run( ProcessFormatter().format( @@ -87,7 +81,6 @@ async def test_git_current_branch_detached(git_repo): assert p.stderr.decode().strip() == "fatal: ref HEAD is not a symbolic ref" -@pytest.mark.asyncio async def test_git_current_commit_on_branch(git_repo): # HEAD on dont_add_commits (a0ccc2390883c85a361f5a90c72e1b07958939fa) # setup @@ -105,7 +98,6 @@ async def test_git_current_commit_on_branch(git_repo): assert p.stdout.decode().strip() == "a0ccc2390883c85a361f5a90c72e1b07958939fa" -@pytest.mark.asyncio async def test_git_current_commit_detached(git_repo): # detached HEAD state (c950fc05a540dd76b944719c2a3302da2e2f3090) await git_repo._run( @@ -122,7 +114,6 @@ async def test_git_current_commit_detached(git_repo): assert p.stdout.decode().strip() == "c950fc05a540dd76b944719c2a3302da2e2f3090" -@pytest.mark.asyncio async def test_git_latest_commit(git_repo): # HEAD on dont_add_commits (a0ccc2390883c85a361f5a90c72e1b07958939fa) p = await git_repo._run( @@ -134,7 +125,6 @@ async def test_git_latest_commit(git_repo): assert p.stdout.decode().strip() == "a0ccc2390883c85a361f5a90c72e1b07958939fa" -@pytest.mark.asyncio async def test_git_hard_reset(cloned_git_repo, tmp_path): staged_file = cloned_git_repo.folder_path / "staged_file.txt" staged_file.touch() @@ -150,7 +140,6 @@ async def test_git_hard_reset(cloned_git_repo, tmp_path): assert staged_file.exists() is False -@pytest.mark.asyncio async def test_git_pull(git_repo_with_remote, tmp_path): # setup staged_file = Path(git_repo_with_remote.url) / "staged_file.txt" @@ -171,7 +160,6 @@ async def test_git_pull(git_repo_with_remote, tmp_path): assert (git_repo_with_remote.folder_path / "staged_file.txt").exists() -@pytest.mark.asyncio async def test_git_diff_file_status(git_repo): p = await git_repo._run( ProcessFormatter().format( @@ -195,7 +183,6 @@ async def test_git_diff_file_status(git_repo): # might need to add test for test_git_log, but it's unused method currently -@pytest.mark.asyncio async def test_git_discover_remote_url(cloned_git_repo, tmp_path): p = await cloned_git_repo._run( ProcessFormatter().format( @@ -206,7 +193,6 @@ async def test_git_discover_remote_url(cloned_git_repo, tmp_path): assert p.stdout.decode().strip() == cloned_git_repo.url -@pytest.mark.asyncio async def test_git_checkout_detached_head(git_repo): p = await git_repo._run( ProcessFormatter().format( @@ -218,7 +204,6 @@ async def test_git_checkout_detached_head(git_repo): assert p.returncode == 0 -@pytest.mark.asyncio async def test_git_checkout_branch(git_repo): p = await git_repo._run( ProcessFormatter().format( @@ -228,7 +213,6 @@ async def test_git_checkout_branch(git_repo): assert p.returncode == 0 -@pytest.mark.asyncio async def test_git_checkout_non_existent_branch(git_repo): p = await git_repo._run( ProcessFormatter().format( @@ -238,7 +222,6 @@ async def test_git_checkout_non_existent_branch(git_repo): assert p.returncode == 1 -@pytest.mark.asyncio async def test_git_get_full_sha1_from_branch_name(git_repo): p = await git_repo._run( ProcessFormatter().format( @@ -249,7 +232,6 @@ async def test_git_get_full_sha1_from_branch_name(git_repo): assert p.stdout.decode().strip() == "a0ccc2390883c85a361f5a90c72e1b07958939fa" -@pytest.mark.asyncio async def test_git_get_full_sha1_from_full_hash(git_repo): p = await git_repo._run( ProcessFormatter().format( @@ -262,7 +244,6 @@ async def test_git_get_full_sha1_from_full_hash(git_repo): assert p.stdout.decode().strip() == "c950fc05a540dd76b944719c2a3302da2e2f3090" -@pytest.mark.asyncio async def test_git_get_full_sha1_from_short_hash(git_repo): p = await git_repo._run( ProcessFormatter().format( @@ -273,7 +254,6 @@ async def test_git_get_full_sha1_from_short_hash(git_repo): assert p.stdout.decode().strip() == "c950fc05a540dd76b944719c2a3302da2e2f3090" -@pytest.mark.asyncio async def test_git_get_full_sha1_from_too_short_hash(git_repo): p = await git_repo._run( ProcessFormatter().format(git_repo.GIT_GET_FULL_SHA1, path=git_repo.folder_path, rev="c95") @@ -282,7 +262,6 @@ async def test_git_get_full_sha1_from_too_short_hash(git_repo): assert p.stderr.decode().strip() == "fatal: Needed a single revision" -@pytest.mark.asyncio async def test_git_get_full_sha1_from_lightweight_tag(git_repo): p = await git_repo._run( ProcessFormatter().format( @@ -293,7 +272,6 @@ async def test_git_get_full_sha1_from_lightweight_tag(git_repo): assert p.stdout.decode().strip() == "fb99eb7d2d5bed514efc98fe6686b368f8425745" -@pytest.mark.asyncio async def test_git_get_full_sha1_from_annotated_tag(git_repo): p = await git_repo._run( ProcessFormatter().format( @@ -304,7 +282,6 @@ async def test_git_get_full_sha1_from_annotated_tag(git_repo): assert p.stdout.decode().strip() == "a7120330cc179396914e0d6af80cfa282adc124b" -@pytest.mark.asyncio async def test_git_get_full_sha1_from_invalid_ref(git_repo): p = await git_repo._run( ProcessFormatter().format( @@ -318,7 +295,6 @@ async def test_git_get_full_sha1_from_invalid_ref(git_repo): @pytest.mark.skipif( GIT_VERSION < (2, 31), reason="This is test for output from Git 2.31 and newer." ) -@pytest.mark.asyncio async def test_git_get_full_sha1_from_ambiguous_commits(git_repo): # 2 ambiguous refs: # branch ambiguous_1 - 95da0b576271cb5bee5f3e075074c03ee05fed05 @@ -341,7 +317,6 @@ async def test_git_get_full_sha1_from_ambiguous_commits(git_repo): @pytest.mark.skipif( GIT_VERSION < (2, 36), reason="This is test for output from Git 2.36 and newer." ) -@pytest.mark.asyncio async def test_git_get_full_sha1_from_ambiguous_tag_and_commit(git_repo): # 2 ambiguous refs: # branch ambiguous_with_tag - c6f0e5ec04d99bdf8c6c78ff20d66d286eecb3ea @@ -364,7 +339,6 @@ async def test_git_get_full_sha1_from_ambiguous_tag_and_commit(git_repo): @pytest.mark.skipif( not ((2, 31) <= GIT_VERSION < (2, 36)), reason="This is test for output from Git >=2.31,<2.36." ) -@pytest.mark.asyncio async def test_git_get_full_sha1_from_ambiguous_tag_and_commit_pre_2_36(git_repo): # 2 ambiguous refs: # branch ambiguous_with_tag - c6f0e5ec04d99bdf8c6c78ff20d66d286eecb3ea @@ -387,7 +361,6 @@ async def test_git_get_full_sha1_from_ambiguous_tag_and_commit_pre_2_36(git_repo @pytest.mark.skipif( GIT_VERSION >= (2, 31), reason="This is test for output from Git older than 2.31." ) -@pytest.mark.asyncio async def test_git_get_full_sha1_from_ambiguous_commits_pre_2_31(git_repo): # 2 ambiguous refs: # branch ambiguous_1 - 95da0b576271cb5bee5f3e075074c03ee05fed05 @@ -410,7 +383,6 @@ async def test_git_get_full_sha1_from_ambiguous_commits_pre_2_31(git_repo): @pytest.mark.skipif( GIT_VERSION >= (2, 31), reason="This is test for output from Git older than 2.31." ) -@pytest.mark.asyncio async def test_git_get_full_sha1_from_ambiguous_tag_and_commit_pre_2_31(git_repo): # 2 ambiguous refs: # branch ambiguous_with_tag - c6f0e5ec04d99bdf8c6c78ff20d66d286eecb3ea @@ -430,7 +402,6 @@ async def test_git_get_full_sha1_from_ambiguous_tag_and_commit_pre_2_31(git_repo ) -@pytest.mark.asyncio async def test_git_is_ancestor_true(git_repo): p = await git_repo._run( ProcessFormatter().format( @@ -443,7 +414,6 @@ async def test_git_is_ancestor_true(git_repo): assert p.returncode == 0 -@pytest.mark.asyncio async def test_git_is_ancestor_false(git_repo): p = await git_repo._run( ProcessFormatter().format( @@ -456,7 +426,6 @@ async def test_git_is_ancestor_false(git_repo): assert p.returncode == 1 -@pytest.mark.asyncio async def test_git_is_ancestor_invalid_object(git_repo): p = await git_repo._run( ProcessFormatter().format( @@ -470,7 +439,6 @@ async def test_git_is_ancestor_invalid_object(git_repo): assert p.stderr.decode().strip() == "fatal: Not a valid object name invalid1" -@pytest.mark.asyncio async def test_git_is_ancestor_invalid_commit(git_repo): p = await git_repo._run( ProcessFormatter().format( @@ -486,7 +454,6 @@ async def test_git_is_ancestor_invalid_commit(git_repo): ) -@pytest.mark.asyncio async def test_git_check_if_module_exists_true(git_repo): p = await git_repo._run( ProcessFormatter().format( @@ -502,7 +469,6 @@ async def test_git_check_if_module_exists_true(git_repo): @pytest.mark.skipif( GIT_VERSION < (2, 36), reason="This is test for output from Git 2.36 and newer." ) -@pytest.mark.asyncio async def test_git_check_if_module_exists_false(git_repo): p = await git_repo._run( ProcessFormatter().format( @@ -521,7 +487,6 @@ async def test_git_check_if_module_exists_false(git_repo): @pytest.mark.skipif( GIT_VERSION >= (2, 36), reason="This is test for output from Git older than 2.31." ) -@pytest.mark.asyncio async def test_git_check_if_module_exists_false_pre_2_36(git_repo): p = await git_repo._run( ProcessFormatter().format( @@ -537,7 +502,6 @@ async def test_git_check_if_module_exists_false_pre_2_36(git_repo): ) -@pytest.mark.asyncio async def test_git_find_last_occurrence_existent(git_repo): p = await git_repo._run( ProcessFormatter().format( @@ -552,7 +516,6 @@ async def test_git_find_last_occurrence_existent(git_repo): assert p.stdout.decode().strip() == "a7120330cc179396914e0d6af80cfa282adc124b" -@pytest.mark.asyncio async def test_git_find_last_occurrence_non_existent(git_repo): p = await git_repo._run( ProcessFormatter().format( diff --git a/tests/cogs/test_alias.py b/tests/cogs/test_alias.py index 27fdc9833..261c85dcb 100644 --- a/tests/cogs/test_alias.py +++ b/tests/cogs/test_alias.py @@ -7,12 +7,10 @@ def test_is_valid_alias_name(alias): assert alias.is_valid_alias_name("not valid name") is False -@pytest.mark.asyncio async def test_empty_guild_aliases(alias, empty_guild): assert list(await alias._aliases.get_guild_aliases(empty_guild)) == [] -@pytest.mark.asyncio async def test_empty_global_aliases(alias): assert list(await alias._aliases.get_global_aliases()) == [] @@ -25,7 +23,6 @@ async def create_test_global_alias(alias, ctx): await alias._aliases.add_alias(ctx, "test_global", "ping", global_=True) -@pytest.mark.asyncio async def test_add_guild_alias(alias, ctx): await create_test_guild_alias(alias, ctx) @@ -33,7 +30,6 @@ async def test_add_guild_alias(alias, ctx): assert alias_obj.name == "test" -@pytest.mark.asyncio async def test_delete_guild_alias(alias, ctx): await create_test_guild_alias(alias, ctx) alias_obj = await alias._aliases.get_alias(ctx.guild, "test") @@ -46,7 +42,6 @@ async def test_delete_guild_alias(alias, ctx): assert alias_obj is None -@pytest.mark.asyncio async def test_add_global_alias(alias, ctx): await create_test_global_alias(alias, ctx) alias_obj = await alias._aliases.get_alias(ctx.guild, "test_global") @@ -54,7 +49,6 @@ async def test_add_global_alias(alias, ctx): assert alias_obj.name == "test_global" -@pytest.mark.asyncio async def test_delete_global_alias(alias, ctx): await create_test_global_alias(alias, ctx) alias_obj = await alias._aliases.get_alias(ctx.guild, "test_global") diff --git a/tests/cogs/test_economy.py b/tests/cogs/test_economy.py index ec7190339..e53bec9d0 100644 --- a/tests/cogs/test_economy.py +++ b/tests/cogs/test_economy.py @@ -2,7 +2,6 @@ import pytest from redbot.pytest.economy import * -@pytest.mark.asyncio async def test_bank_register(bank, ctx): default_bal = await bank.get_default_balance(ctx.guild) assert default_bal == (await bank.get_account(ctx.author)).balance @@ -15,7 +14,6 @@ async def has_account(member, bank): await bank.set_balance(member, balance) -@pytest.mark.asyncio async def test_bank_transfer(bank, member_factory): mbr1 = member_factory.get() mbr2 = member_factory.get() @@ -28,7 +26,6 @@ async def test_bank_transfer(bank, member_factory): assert bal2 + 50 == newbal2 -@pytest.mark.asyncio async def test_bank_set(bank, member_factory): mbr = member_factory.get() await bank.set_balance(mbr, 250) @@ -36,7 +33,6 @@ async def test_bank_set(bank, member_factory): assert acc.balance == 250 -@pytest.mark.asyncio async def test_bank_can_spend(bank, member_factory): mbr = member_factory.get() canspend = await bank.can_spend(mbr, 50) @@ -47,7 +43,6 @@ async def test_bank_can_spend(bank, member_factory): assert canspendnow -@pytest.mark.asyncio async def test_set_bank_name(bank, guild_factory): guild = guild_factory.get() await bank.set_bank_name("Test Bank", guild) @@ -55,7 +50,6 @@ async def test_set_bank_name(bank, guild_factory): assert name == "Test Bank" -@pytest.mark.asyncio async def test_set_currency_name(bank, guild_factory): guild = guild_factory.get() await bank.set_currency_name("Coins", guild) @@ -63,7 +57,6 @@ async def test_set_currency_name(bank, guild_factory): assert name == "Coins" -@pytest.mark.asyncio async def test_set_default_balance(bank, guild_factory): guild = guild_factory.get() await bank.set_default_balance(500, guild) @@ -71,7 +64,6 @@ async def test_set_default_balance(bank, guild_factory): assert default_bal == 500 -@pytest.mark.asyncio async def test_nonint_transaction_amount(bank, member_factory): mbr1 = member_factory.get() mbr2 = member_factory.get() diff --git a/tests/cogs/test_mod.py b/tests/cogs/test_mod.py index 0d2908a4f..01c2a8d15 100644 --- a/tests/cogs/test_mod.py +++ b/tests/cogs/test_mod.py @@ -3,14 +3,12 @@ import pytest from redbot.pytest.mod import * -@pytest.mark.asyncio async def test_modlog_register_casetype(mod): ct = {"name": "ban", "default_setting": True, "image": ":hammer:", "case_str": "Ban"} casetype = await mod.register_casetype(**ct) assert casetype is not None -@pytest.mark.asyncio async def test_modlog_case_create(mod, ctx, member_factory): from datetime import datetime, timezone @@ -33,7 +31,6 @@ async def test_modlog_case_create(mod, ctx, member_factory): assert case.created_at == int(created_at.timestamp()) -@pytest.mark.asyncio async def test_modlog_set_modlog_channel(mod, ctx): await mod.set_modlog_channel(ctx.guild, ctx.channel) assert await mod.get_modlog_channel(ctx.guild) == ctx.channel.id diff --git a/tests/core/test_cog_manager.py b/tests/core/test_cog_manager.py index cc34d6f01..ac85e3290 100644 --- a/tests/core/test_cog_manager.py +++ b/tests/core/test_cog_manager.py @@ -7,20 +7,17 @@ from redbot.core import cog_manager @pytest.mark.skip -@pytest.mark.asyncio async def test_ensure_cogs_in_paths(cog_mgr, default_dir): cogs_dir = default_dir / "redbot" / "cogs" assert cogs_dir in await cog_mgr.paths() -@pytest.mark.asyncio async def test_install_path_set(cog_mgr: cog_manager.CogManager, tmpdir): path = Path(str(tmpdir)) await cog_mgr.set_install_path(path) assert await cog_mgr.install_path() == path -@pytest.mark.asyncio async def test_install_path_set_bad(cog_mgr): path = Path("something") @@ -28,14 +25,12 @@ async def test_install_path_set_bad(cog_mgr): await cog_mgr.set_install_path(path) -@pytest.mark.asyncio async def test_add_path(cog_mgr, tmpdir): path = Path(str(tmpdir)) await cog_mgr.add_path(path) assert path in await cog_mgr.paths() -@pytest.mark.asyncio async def test_add_path_already_install_path(cog_mgr, tmpdir): path = Path(str(tmpdir)) await cog_mgr.set_install_path(path) @@ -43,7 +38,6 @@ async def test_add_path_already_install_path(cog_mgr, tmpdir): await cog_mgr.add_path(path) -@pytest.mark.asyncio async def test_remove_path(cog_mgr, tmpdir): path = Path(str(tmpdir)) await cog_mgr.add_path(path) diff --git a/tests/core/test_config.py b/tests/core/test_config.py index bef10426d..ac34ae688 100644 --- a/tests/core/test_config.py +++ b/tests/core/test_config.py @@ -5,7 +5,6 @@ from collections import Counter # region Register Tests -@pytest.mark.asyncio async def test_config_register_global(config): config.register_global(enabled=False) assert config.defaults["GLOBAL"]["enabled"] is False @@ -17,7 +16,6 @@ def test_config_register_global_badvalues(config): config.register_global(**{"invalid var name": True}) -@pytest.mark.asyncio async def test_config_register_guild(config, empty_guild): config.register_guild(enabled=False, some_list=[], some_dict={}) assert config.defaults[config.GUILD]["enabled"] is False @@ -29,35 +27,30 @@ async def test_config_register_guild(config, empty_guild): assert await config.guild(empty_guild).some_dict() == {} -@pytest.mark.asyncio async def test_config_register_channel(config, empty_channel): config.register_channel(enabled=False) assert config.defaults[config.CHANNEL]["enabled"] is False assert await config.channel(empty_channel).enabled() is False -@pytest.mark.asyncio async def test_config_register_role(config, empty_role): config.register_role(enabled=False) assert config.defaults[config.ROLE]["enabled"] is False assert await config.role(empty_role).enabled() is False -@pytest.mark.asyncio async def test_config_register_member(config, empty_member): config.register_member(some_number=-1) assert config.defaults[config.MEMBER]["some_number"] == -1 assert await config.member(empty_member).some_number() == -1 -@pytest.mark.asyncio async def test_config_register_user(config, empty_user): config.register_user(some_value=None) assert config.defaults[config.USER]["some_value"] is None assert await config.user(empty_user).some_value() is None -@pytest.mark.asyncio async def test_config_force_register_global(config_fr): with pytest.raises(AttributeError): await config_fr.enabled() @@ -70,13 +63,11 @@ async def test_config_force_register_global(config_fr): # Test nested registration -@pytest.mark.asyncio async def test_nested_registration(config): config.register_global(foo__bar__baz=False) assert await config.foo.bar.baz() is False -@pytest.mark.asyncio async def test_nested_registration_asdict(config): defaults = {"bar": {"baz": False}} config.register_global(foo=defaults) @@ -84,7 +75,6 @@ async def test_nested_registration_asdict(config): assert await config.foo.bar.baz() is False -@pytest.mark.asyncio async def test_nested_registration_and_changing(config): defaults = {"bar": {"baz": False}} config.register_global(foo=defaults) @@ -95,7 +85,6 @@ async def test_nested_registration_and_changing(config): await config.foo.set(True) -@pytest.mark.asyncio async def test_doubleset_default(config): config.register_global(foo=True) config.register_global(foo=False) @@ -103,7 +92,6 @@ async def test_doubleset_default(config): assert await config.foo() is False -@pytest.mark.asyncio async def test_nested_registration_multidict(config): defaults = {"foo": {"bar": {"baz": True}}, "blah": True} config.register_global(**defaults) @@ -118,7 +106,6 @@ def test_nested_group_value_badreg(config): config.register_global(foo__bar=False) -@pytest.mark.asyncio async def test_nested_toplevel_reg(config): defaults = {"bar": True, "baz": False} config.register_global(foo=defaults) @@ -127,7 +114,6 @@ async def test_nested_toplevel_reg(config): assert await config.foo.baz() is False -@pytest.mark.asyncio async def test_nested_overlapping(config): config.register_global(foo__bar=True) config.register_global(foo__baz=False) @@ -136,7 +122,6 @@ async def test_nested_overlapping(config): assert await config.foo.baz() is False -@pytest.mark.asyncio async def test_nesting_nofr(config): config.register_global(foo={}) assert await config.foo.bar() is None @@ -144,38 +129,31 @@ async def test_nesting_nofr(config): # region Default Value Overrides -@pytest.mark.asyncio async def test_global_default_override(config): assert await config.enabled(True) is True -@pytest.mark.asyncio async def test_global_default_nofr(config): assert await config.nofr() is None assert await config.nofr(True) is True -@pytest.mark.asyncio async def test_guild_default_override(config, empty_guild): assert await config.guild(empty_guild).enabled(True) is True -@pytest.mark.asyncio async def test_channel_default_override(config, empty_channel): assert await config.channel(empty_channel).enabled(True) is True -@pytest.mark.asyncio async def test_role_default_override(config, empty_role): assert await config.role(empty_role).enabled(True) is True -@pytest.mark.asyncio async def test_member_default_override(config, empty_member): assert await config.member(empty_member).enabled(True) is True -@pytest.mark.asyncio async def test_user_default_override(config, empty_user): assert await config.user(empty_user).some_value(True) is True @@ -184,13 +162,11 @@ async def test_user_default_override(config, empty_user): # region Setting Values -@pytest.mark.asyncio async def test_set_global(config): await config.enabled.set(True) assert await config.enabled() is True -@pytest.mark.asyncio async def test_set_guild(config, empty_guild): await config.guild(empty_guild).enabled.set(True) assert await config.guild(empty_guild).enabled() is True @@ -203,13 +179,11 @@ async def test_set_guild(config, empty_guild): assert await config.guild(empty_guild).some_list() == curr_list -@pytest.mark.asyncio async def test_set_channel(config, empty_channel): await config.channel(empty_channel).enabled.set(True) assert await config.channel(empty_channel).enabled() is True -@pytest.mark.asyncio async def test_set_channel_no_register(config, empty_channel): await config.channel(empty_channel).no_register.set(True) assert await config.channel(empty_channel).no_register() is True @@ -219,14 +193,12 @@ async def test_set_channel_no_register(config, empty_channel): # Dynamic attribute testing -@pytest.mark.asyncio async def test_set_dynamic_attr(config): await config.set_raw("foobar", value=True) assert await config.foobar() is True -@pytest.mark.asyncio async def test_clear_dynamic_attr(config): await config.foo.set(True) await config.clear_raw("foo") @@ -235,13 +207,11 @@ async def test_clear_dynamic_attr(config): await config.get_raw("foo") -@pytest.mark.asyncio async def test_get_dynamic_attr(config): assert await config.get_raw("foobaz", default=True) is True # Member Group testing -@pytest.mark.asyncio async def test_membergroup_allguilds(config, empty_member): await config.member(empty_member).foo.set(False) @@ -249,7 +219,6 @@ async def test_membergroup_allguilds(config, empty_member): assert empty_member.guild.id in all_servers -@pytest.mark.asyncio async def test_membergroup_allmembers(config, empty_member): await config.member(empty_member).foo.set(False) @@ -258,7 +227,6 @@ async def test_membergroup_allmembers(config, empty_member): # Clearing testing -@pytest.mark.asyncio async def test_global_clear(config): config.register_global(foo=True, bar=False) @@ -274,7 +242,6 @@ async def test_global_clear(config): assert await config.bar() is False -@pytest.mark.asyncio async def test_member_clear(config, member_factory): config.register_member(foo=True) @@ -293,7 +260,6 @@ async def test_member_clear(config, member_factory): assert await config.member(m2).foo() is False -@pytest.mark.asyncio async def test_member_clear_all(config, member_factory): server_ids = [] for _ in range(5): @@ -309,7 +275,6 @@ async def test_member_clear_all(config, member_factory): assert len(await config.all_members()) == 0 -@pytest.mark.asyncio async def test_clear_all(config): await config.foo.set(True) assert await config.foo() is True @@ -319,7 +284,6 @@ async def test_clear_all(config): await config.get_raw("foo") -@pytest.mark.asyncio async def test_clear_value(config): await config.foo.set(True) await config.foo.clear() @@ -329,7 +293,6 @@ async def test_clear_value(config): # Get All testing -@pytest.mark.asyncio async def test_user_get_all_from_kind(config, user_factory): config.register_user(foo=False, bar=True) for _ in range(5): @@ -345,7 +308,6 @@ async def test_user_get_all_from_kind(config, user_factory): assert v["bar"] is True -@pytest.mark.asyncio async def test_user_getalldata(config, user_factory): user = user_factory.get() config.register_user(foo=True, bar=False) @@ -359,7 +321,6 @@ async def test_user_getalldata(config, user_factory): assert config.user(user).defaults["foo"] is True -@pytest.mark.asyncio async def test_value_ctxmgr(config): config.register_global(foo_list=[]) @@ -371,7 +332,6 @@ async def test_value_ctxmgr(config): assert "foo" in foo_list -@pytest.mark.asyncio async def test_value_ctxmgr_saves(config): config.register_global(bar_list=[]) @@ -387,7 +347,6 @@ async def test_value_ctxmgr_saves(config): assert "bar" in bar_list -@pytest.mark.asyncio async def test_value_ctxmgr_immutable(config): config.register_global(foo=True) @@ -399,7 +358,6 @@ async def test_value_ctxmgr_immutable(config): assert foo is True -@pytest.mark.asyncio async def test_ctxmgr_no_shared_default(config, member_factory): config.register_member(foo=[]) m1 = member_factory.get() @@ -411,7 +369,6 @@ async def test_ctxmgr_no_shared_default(config, member_factory): assert 1 not in await config.member(m2).foo() -@pytest.mark.asyncio async def test_ctxmgr_no_unnecessary_write(config): config.register_global(foo=[]) foo_value_obj = config.foo @@ -421,7 +378,6 @@ async def test_ctxmgr_no_unnecessary_write(config): set_method.assert_not_called() -@pytest.mark.asyncio async def test_get_then_mutate(config): """Tests that mutating an object after getting it as a value doesn't mutate the data store.""" config.register_global(list1=[]) @@ -432,7 +388,6 @@ async def test_get_then_mutate(config): assert "foo" not in list1 -@pytest.mark.asyncio async def test_set_then_mutate(config): """Tests that mutating an object after setting it as a value doesn't mutate the data store.""" config.register_global(list1=[]) @@ -443,14 +398,12 @@ async def test_set_then_mutate(config): assert "foo" not in list1 -@pytest.mark.asyncio async def test_call_group_fills_defaults(config): config.register_global(subgroup={"foo": True}) subgroup = await config.subgroup() assert "foo" in subgroup -@pytest.mark.asyncio async def test_group_call_ctxmgr_writes(config): config.register_global(subgroup={"foo": True}) async with config.subgroup() as subgroup: @@ -460,7 +413,6 @@ async def test_group_call_ctxmgr_writes(config): assert subgroup == {"foo": True, "bar": False} -@pytest.mark.asyncio async def test_all_works_as_ctxmgr(config): config.register_global(subgroup={"foo": True}) async with config.subgroup.all() as subgroup: @@ -470,7 +422,6 @@ async def test_all_works_as_ctxmgr(config): assert subgroup == {"foo": True, "bar": False} -@pytest.mark.asyncio async def test_get_raw_mixes_defaults(config): config.register_global(subgroup={"foo": True}) await config.subgroup.set_raw("bar", value=False) @@ -479,7 +430,6 @@ async def test_get_raw_mixes_defaults(config): assert subgroup == {"foo": True, "bar": False} -@pytest.mark.asyncio async def test_cast_str_raw(config): await config.set_raw(123, 456, value=True) assert await config.get_raw(123, 456) is True @@ -487,7 +437,6 @@ async def test_cast_str_raw(config): await config.clear_raw("123", 456) -@pytest.mark.asyncio async def test_cast_str_nested(config): config.register_global(foo={}) await config.foo.set({123: True, 456: {789: False}}) @@ -510,7 +459,6 @@ def test_config_custom_doubleinit(config): config.init_custom("TEST", 2) -@pytest.mark.asyncio async def test_config_locks_cache(config, empty_guild): lock1 = config.foo.get_lock() assert lock1 is config.foo.get_lock() @@ -519,7 +467,6 @@ async def test_config_locks_cache(config, empty_guild): assert lock1 is not lock2 -@pytest.mark.asyncio async def test_config_value_atomicity(config): config.register_global(foo=[]) tasks = [] @@ -539,7 +486,6 @@ async def test_config_value_atomicity(config): assert len(await config.foo()) == 15 -@pytest.mark.asyncio async def test_config_ctxmgr_atomicity(config): config.register_global(foo=[]) tasks = [] @@ -557,7 +503,6 @@ async def test_config_ctxmgr_atomicity(config): assert len(await config.foo()) == 15 -@pytest.mark.asyncio async def test_set_with_partial_primary_keys(config): config.init_custom("CUSTOM", 3) await config.custom("CUSTOM", "1").set({"11": {"111": {"foo": "bar"}}}) @@ -585,7 +530,6 @@ async def test_set_with_partial_primary_keys(config): assert await config.custom("CUSTOM", "2", "33", "222").foo() == "biz" -@pytest.mark.asyncio async def test_raw_with_partial_primary_keys(config): config.init_custom("CUSTOM", 1) await config.custom("CUSTOM").set_raw("primary_key", "identifier", value=True) @@ -654,7 +598,6 @@ PARAMS = [ @pytest.mark.parametrize("pkeys, raw_args, result", PARAMS) -@pytest.mark.asyncio async def test_config_custom_partial_pkeys_get(config, pkeys, raw_args, result): # setup config.init_custom("TEST", 3) @@ -666,7 +609,6 @@ async def test_config_custom_partial_pkeys_get(config, pkeys, raw_args, result): @pytest.mark.parametrize("pkeys, raw_args, result", PARAMS) -@pytest.mark.asyncio async def test_config_custom_partial_pkeys_set(config, pkeys, raw_args, result): # setup config.init_custom("TEST", 3) diff --git a/tests/core/test_installation.py b/tests/core/test_installation.py index dae662be4..3023c8697 100644 --- a/tests/core/test_installation.py +++ b/tests/core/test_installation.py @@ -1,6 +1,5 @@ import pytest -@pytest.mark.asyncio async def test_can_init_bot(red): assert red is not None diff --git a/tests/core/test_utils.py b/tests/core/test_utils.py index 69d22efd4..1981cfcfc 100644 --- a/tests/core/test_utils.py +++ b/tests/core/test_utils.py @@ -15,7 +15,6 @@ def test_deduplicate_iterables(): assert deduplicate_iterables(*inputs) == expected -@pytest.mark.asyncio async def test_bounded_gather(): status = [0, 0] # num_running, max_running @@ -52,7 +51,6 @@ async def test_bounded_gather(): assert num_fail == num_failed -@pytest.mark.asyncio async def test_bounded_gather_iter(): status = [0, 0] # num_running, max_running @@ -91,7 +89,6 @@ async def test_bounded_gather_iter(): @pytest.mark.skip(reason="spams logs with pending task warnings") -@pytest.mark.asyncio async def test_bounded_gather_iter_cancel(): status = [0, 0, 0] # num_running, max_running, num_ran diff --git a/tests/core/test_version.py b/tests/core/test_version.py index a978e270a..954ce8947 100644 --- a/tests/core/test_version.py +++ b/tests/core/test_version.py @@ -73,7 +73,7 @@ def test_python_version_has_lower_bound(): @pytest.mark.skipif( - os.getenv("TOX_RED", False) and sys.version_info >= (3, 10), + os.getenv("TOX_RED", False) and sys.version_info >= (3, 12), reason="Testing on yet to be supported Python version.", ) def test_python_version_has_upper_bound(): diff --git a/tools/dev-requirements.txt b/tools/dev-requirements.txt index d99485829..7e6fd0def 100644 --- a/tools/dev-requirements.txt +++ b/tools/dev-requirements.txt @@ -1,2 +1,2 @@ -tox<4 +tox -e .[dev] diff --git a/tox.ini b/tox.ini index 14f1479c4..de84c457a 100644 --- a/tox.ini +++ b/tox.ini @@ -7,14 +7,15 @@ envlist = py38 py39 + py310 + py311 docs style skip_missing_interpreters = True -isolated_build = True [testenv] description = Run tests and basic automatic issue checking. -whitelist_externals = +allowlist_externals = pytest pylint extras = test @@ -27,7 +28,7 @@ commands = [testenv:postgres] description = Run pytest with PostgreSQL backend -whitelist_externals = +allowlist_externals = pytest extras = test, postgres setenv = @@ -46,7 +47,7 @@ commands = [testenv:docs] description = Attempt to build docs with sphinx-build -whitelist_externals = +allowlist_externals = sphinx-build make setenv = @@ -61,7 +62,7 @@ commands = [testenv:style] description = Stylecheck the code with black to see if anything needs changes. -whitelist_externals = +allowlist_externals = make setenv = # This is just for Windows