Make some dependency changes, support Python 3.10 and 3.11 (#5611)

Co-authored-by: jack1142 <6032823+jack1142@users.noreply.github.com>
This commit is contained in:
Jakub Kuczys 2022-12-30 03:21:57 +01:00 committed by GitHub
parent d3308af0e2
commit 519acedf46
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
59 changed files with 324 additions and 373 deletions

View File

@ -27,8 +27,11 @@ jobs:
python_version: "3.9" python_version: "3.9"
friendly_name: Python 3.9 - Tests friendly_name: Python 3.9 - Tests
- tox_env: py310 - tox_env: py310
python_version: "3.10-dev" python_version: "3.10"
friendly_name: Python 3.10-dev - Tests friendly_name: Python 3.10 - Tests
- tox_env: py311
python_version: "3.11"
friendly_name: Python 3.11 - Tests
- tox_env: style - tox_env: style
friendly_name: Style friendly_name: Style
- tox_env: docs - tox_env: docs
@ -46,7 +49,7 @@ jobs:
- name: Install tox - name: Install tox
run: | run: |
python -m pip install --upgrade pip python -m pip install --upgrade pip
pip install 'tox<4' pip install tox
- name: Tox test - name: Tox test
env: env:
TOXENV: ${{ matrix.tox_env }} TOXENV: ${{ matrix.tox_env }}
@ -59,7 +62,8 @@ jobs:
python_version: python_version:
- "3.8" - "3.8"
- "3.9" - "3.9"
- "3.10-dev" - "3.10"
- "3.11"
fail-fast: false fail-fast: false
name: Tox - Postgres name: Tox - Postgres
services: services:
@ -82,7 +86,7 @@ jobs:
- name: Install tox - name: Install tox
run: | run: |
python -m pip install --upgrade pip python -m pip install --upgrade pip
pip install 'tox<4' pip install tox
- name: Tox test - name: Tox test
env: env:
TOXENV: postgres TOXENV: postgres

View File

@ -267,7 +267,7 @@ customcom search
Searches through custom commands, according to the query. Searches through custom commands, according to the query.
Uses fuzzywuzzy searching to find close matches. Uses fuzzy searching to find close matches.
**Arguments:** **Arguments:**

View File

@ -82,7 +82,7 @@ release = __version__
# #
# This is also used if you do content translation via gettext catalogs. # This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases. # 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 # List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files. # directories to ignore when looking for source files.
@ -246,8 +246,8 @@ intersphinx_mapping = {
# :dpy_docs:`link text <site_name.html>` # :dpy_docs:`link text <site_name.html>`
extlinks = { extlinks = {
"dpy_docs": (f"{dpy_docs_url}/%s", None), "dpy_docs": (f"{dpy_docs_url}/%s", None),
"issue": ("https://github.com/Cog-Creators/Red-DiscordBot/issues/%s", "#"), "issue": ("https://github.com/Cog-Creators/Red-DiscordBot/issues/%s", "#%s"),
"ghuser": ("https://github.com/%s", "@"), "ghuser": ("https://github.com/%s", "@%s"),
} }
# Doctest # Doctest

View File

@ -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. ``redenv`` and it will be located in your home directory.
Create your virtual environment with the following command: 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.

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -13,7 +13,7 @@ Install them with dnf:
sudo dnf -y update sudo dnf -y update
sudo dnf -y group install development 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: Set ``java`` executable to point to Java 11:
@ -23,6 +23,6 @@ Set ``java`` executable to point to Java 11:
.. Include common instructions: .. 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 .. include:: _includes/install-and-setup-red-unix.rst

View File

@ -11,10 +11,10 @@ Install them with dnf:
.. prompt:: bash .. 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 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 .. include:: _includes/install-and-setup-red-unix.rst

View File

@ -2,7 +2,7 @@
Installing Python with pyenv 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 This simplifies the compilation process and has the added bonus of simplifying setting up Red in a
virtual environment. virtual environment.
@ -10,7 +10,7 @@ virtual environment.
.. prompt:: bash .. 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 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 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 .. 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.

View File

@ -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.

View File

@ -2,7 +2,7 @@
Installing Python with pyenv 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 This simplifies the compilation process and has the added bonus of simplifying setting up Red in a
virtual environment. virtual environment.
@ -10,7 +10,7 @@ virtual environment.
.. prompt:: bash .. 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 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 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 .. 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.

View File

@ -16,10 +16,22 @@ Install the pre-requirements with pacman:
.. prompt:: bash .. 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 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 .. include:: _includes/install-and-setup-red-unix.rst

View File

@ -37,7 +37,9 @@ In order to install Git 2.11 or greater, we recommend adding the IUS repository:
.. Include common instructions: .. 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 .. include:: _includes/create-env-with-pyenv-virtualenv.rst

View File

@ -18,7 +18,7 @@ Debian Buster. This guide will tell you how. First, run the following commands:
.. prompt:: bash .. prompt:: bash
sudo apt update 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++ CXX=/usr/bin/g++
.. Include common instructions: .. Include common instructions:

View File

@ -18,10 +18,10 @@ with apt:
.. prompt:: bash .. prompt:: bash
sudo apt update 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 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 .. include:: _includes/install-and-setup-red-unix.rst

View File

@ -17,10 +17,10 @@ them with dnf:
.. prompt:: bash .. 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 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 .. include:: _includes/install-and-setup-red-unix.rst

View File

@ -23,7 +23,7 @@ one-by-one:
.. prompt:: bash .. prompt:: bash
brew install python@3.9 brew install python@3.11
brew install git brew install git
brew tap homebrew/cask-versions brew tap homebrew/cask-versions
brew install --cask temurin11 brew install --cask temurin11
@ -34,11 +34,11 @@ To fix this, you should run these commands:
.. prompt:: bash .. prompt:: bash
profile=$([ -n "$ZSH_VERSION" ] && echo ~/.zprofile || ([ -f ~/.bash_profile ] && echo ~/.bash_profile || echo ~/.profile)) 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" source "$profile"
.. Include common instructions: .. 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 .. include:: _includes/install-and-setup-red-unix.rst

View File

@ -1,7 +1,7 @@
.. _install-opensuse-leap-15: .. _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 .. include:: _includes/supported-arch-x64+aarch64.rst
@ -12,16 +12,16 @@ Installing Red on openSUSE Leap 15.3+
Installing the pre-requirements 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: with zypper:
.. prompt:: bash .. 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 sudo zypper -n install -t pattern devel_basis
.. Include common instructions: .. 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 .. include:: _includes/install-and-setup-red-unix.rst

View File

@ -17,11 +17,11 @@ with zypper:
.. prompt:: bash .. 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 sudo zypper -n install -t pattern devel_basis
.. Include common instructions: .. 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 .. include:: _includes/install-and-setup-red-unix.rst

View File

@ -35,15 +35,20 @@ Installing the pre-requirements
We recommend installing pyenv as a method of installing non-native versions of Python on 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: 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 .. prompt:: bash
sudo apt update 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++ CXX=/usr/bin/g++
.. Include common instructions: .. 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 .. include:: _includes/create-env-with-pyenv-virtualenv.rst

View File

@ -33,10 +33,10 @@ with apt:
.. prompt:: bash .. prompt:: bash
sudo apt update 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 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 .. include:: _includes/install-and-setup-red-unix.rst

View File

@ -12,6 +12,10 @@ Installing Red on Ubuntu 18.04 LTS
Installing the pre-requirements 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: We recommend adding the ``git-core`` ppa to install Git 2.11 or greater:
.. prompt:: bash .. 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 apt -y install software-properties-common
sudo add-apt-repository -y ppa:git-core/ppa 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 .. prompt:: bash
@ -30,10 +34,10 @@ Now install the pre-requirements with apt:
.. prompt:: bash .. 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 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 .. include:: _includes/install-and-setup-red-unix.rst

View File

@ -12,22 +12,16 @@ Installing Red on Ubuntu 20.04 LTS
Installing the pre-requirements 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 .. prompt:: bash
sudo apt update sudo apt update
sudo apt -y install software-properties-common sudo apt -y install python3.9 python3.9-dev python3.9-venv git openjdk-11-jre-headless build-essential nano
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
.. Include common instructions: .. 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 .. include:: _includes/install-and-setup-red-unix.rst

View File

@ -12,22 +12,16 @@ Installing Red on Ubuntu 22.04 LTS
Installing the pre-requirements 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 .. prompt:: bash
sudo apt update sudo apt update
sudo apt -y install software-properties-common sudo apt -y install python3.10 python3.10-dev python3.10-venv git openjdk-11-jre-headless build-essential nano
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
.. Include common instructions: .. 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 .. include:: _includes/install-and-setup-red-unix.rst

View File

@ -12,26 +12,15 @@ Installing Red on Ubuntu non-LTS versions
Installing the pre-requirements 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 .. prompt:: bash
sudo apt update sudo apt update
sudo apt -y install software-properties-common sudo apt -y install python3.11 python3.11-dev python3.11-venv git openjdk-11-jre-headless build-essential nano
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++
.. Include common instructions: .. Include common instructions:
.. include:: _includes/install-python-pyenv.rst .. include:: _includes/create-env-with-venv3.11.rst
.. include:: _includes/create-env-with-pyenv-virtualenv.rst
.. include:: _includes/install-and-setup-red-unix.rst .. include:: _includes/install-and-setup-red-unix.rst

View File

@ -33,7 +33,7 @@ Then run each of the following commands:
iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1')) iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
choco upgrade git --params "/GitOnlyOnPath /WindowsTerminal" -y choco upgrade git --params "/GitOnlyOnPath /WindowsTerminal" -y
choco upgrade visualstudio2022-workload-vctools -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: For Audio support, you should also run the following command before exiting:
@ -57,7 +57,7 @@ Manually installing dependencies
* `MSVC Build tools <https://www.visualstudio.com/downloads/#build-tools-for-visual-studio-2019>`_ * `MSVC Build tools <https://www.visualstudio.com/downloads/#build-tools-for-visual-studio-2019>`_
* `Python 3.8.1 - 3.9.x <https://www.python.org/downloads/windows/>`_ * `Python 3.8.1 - 3.11.x <https://www.python.org/downloads/windows/>`_
.. attention:: Please make sure that the box to add Python to PATH is CHECKED, otherwise .. 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. 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 .. prompt:: batch
py -3.9 -m venv "%userprofile%\redenv" py -3.11 -m venv "%userprofile%\redenv"
And activate it with the following command And activate it with the following command

View File

@ -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 <https://wiki.debian.org/DebianReleases#Production_Releases>`__) Debian 11 Bullseye x86-64, aarch64, armv7l ~2024-09 (`End of life <https://wiki.debian.org/DebianReleases#Production_Releases>`__)
Fedora Linux 35 x86-64, aarch64 2022-11-15 (`End of Life <https://docs.fedoraproject.org/en-US/releases/lifecycle/#_maintenance_schedule>`__) Fedora Linux 35 x86-64, aarch64 2022-11-15 (`End of Life <https://docs.fedoraproject.org/en-US/releases/lifecycle/#_maintenance_schedule>`__)
Fedora Linux 36 x86-64, aarch64 2023-05-16 (`End of Life <https://docs.fedoraproject.org/en-US/releases/lifecycle/#_maintenance_schedule>`__) Fedora Linux 36 x86-64, aarch64 2023-05-16 (`End of Life <https://docs.fedoraproject.org/en-US/releases/lifecycle/#_maintenance_schedule>`__)
openSUSE Leap 15.3 x86-64, aarch64 2022-11-30 (`end of maintenance life cycle <https://en.opensuse.org/Lifetime#openSUSE_Leap>`__)
openSUSE Leap 15.4 x86-64, aarch64 2023-11-30 (`end of maintenance life cycle <https://en.opensuse.org/Lifetime#openSUSE_Leap>`__) openSUSE Leap 15.4 x86-64, aarch64 2023-11-30 (`end of maintenance life cycle <https://en.opensuse.org/Lifetime#openSUSE_Leap>`__)
openSUSE Tumbleweed x86-64, aarch64 forever (support is only provided for an up-to-date system) 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 <https://www.oracle.com/us/support/library/elsp-lifetime-069338.pdf>`__) Oracle Linux 8 x86-64, aarch64 2029-07-31 (`End of Premier Support <https://www.oracle.com/us/support/library/elsp-lifetime-069338.pdf>`__)

View File

@ -20,6 +20,8 @@ classifiers = [
"Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Topic :: Communications :: Chat", "Topic :: Communications :: Chat",
] ]
dynamic = ["version", "requires-python", "dependencies", "optional-dependencies"] dynamic = ["version", "requires-python", "dependencies", "optional-dependencies"]
@ -42,7 +44,7 @@ red-discordbot = "redbot.pytest"
[tool.black] [tool.black]
line-length = 99 line-length = 99
required-version = '22.1.0' required-version = '22'
target-version = ['py38'] target-version = ['py38']
include = '\.py$' include = '\.py$'
force-exclude = ''' force-exclude = '''
@ -50,3 +52,6 @@ force-exclude = '''
redbot\/vendored redbot\/vendored
)/ )/
''' '''
[tool.pytest.ini_options]
asyncio_mode = 'auto'

View File

@ -269,8 +269,12 @@ def _ensure_no_colorama():
from rich.console import detect_legacy_windows from rich.console import detect_legacy_windows
if not detect_legacy_windows(): if not detect_legacy_windows():
import colorama try:
import colorama.initialise import colorama
import colorama.initialise
except ModuleNotFoundError:
# colorama is not Red's primary dependency so it might not be present
return
colorama.deinit() colorama.deinit()
@ -300,8 +304,6 @@ _VERSION = "3.5.0.dev1"
__version__, version_info = VersionInfo._get_version() __version__, version_info = VersionInfo._get_version()
# Filter fuzzywuzzy slow sequence matcher warning
_warnings.filterwarnings("ignore", module=r"fuzzywuzzy.*")
# Show DeprecationWarning # Show DeprecationWarning
_warnings.filterwarnings("default", category=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", module="asyncio",
message="The loop argument is deprecated since Python 3.8", 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",
)

View File

@ -7,7 +7,7 @@ import discord
import lavalink import lavalink
from red_commons.logging import getLogger from red_commons.logging import getLogger
from fuzzywuzzy import process from rapidfuzz import process
from redbot.core import commands from redbot.core import commands
from redbot.core.i18n import Translator from redbot.core.i18n import Translator
from redbot.core.utils import AsyncIter 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_results = process.extract(search_words, to_search_string, limit=50)
search_list = [] 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: if percent_match > 85:
search_list.extend( search_list.extend(
[ [

View File

@ -7,7 +7,7 @@ import discord
import lavalink import lavalink
from red_commons.logging import getLogger from red_commons.logging import getLogger
from fuzzywuzzy import process from rapidfuzz import process
from redbot.core import commands from redbot.core import commands
from redbot.core.i18n import Translator from redbot.core.i18n import Translator
from redbot.core.utils import AsyncIter from redbot.core.utils import AsyncIter
@ -116,7 +116,7 @@ class QueueUtilities(MixinMeta, metaclass=CompositeMetaClass):
async def _build_queue_search_list( async def _build_queue_search_list(
self, queue_list: List[lavalink.Track], search_words: str self, queue_list: List[lavalink.Track], search_words: str
) -> List[Tuple[int, str]]: ) -> List[Tuple[int, str]]:
track_list = [] tracks = {}
async for queue_idx, track in AsyncIter(queue_list).enumerate(start=1): async for queue_idx, track in AsyncIter(queue_list).enumerate(start=1):
if not self.match_url(track.uri): if not self.match_url(track.uri):
query = Query.process_input(track, self.local_folder_current_path) query = Query.process_input(track, self.local_folder_current_path)
@ -131,14 +131,12 @@ class QueueUtilities(MixinMeta, metaclass=CompositeMetaClass):
else: else:
track_title = track.title track_title = track.title
song_info = {str(queue_idx): track_title} tracks[queue_idx] = track_title
track_list.append(song_info) search_results = process.extract(search_words, tracks, limit=50)
search_results = process.extract(search_words, track_list, limit=50)
search_list = [] search_list = []
async for search, percent_match in AsyncIter(search_results): async for title, percent_match, queue_position in AsyncIter(search_results):
async for queue_position, title in AsyncIter(search.items()): if percent_match > 89:
if percent_match > 89: search_list.append((queue_position, title))
search_list.append((queue_position, title))
return search_list return search_list
async def _build_queue_search_page( async def _build_queue_search_page(

View File

@ -7,7 +7,7 @@ from typing import Iterable, List, Mapping, Tuple, Dict, Set, Literal, Union
from urllib.parse import quote_plus from urllib.parse import quote_plus
import discord import discord
from fuzzywuzzy import process from rapidfuzz import process
from redbot.core import Config, checks, commands from redbot.core import Config, checks, commands
from redbot.core.i18n import Translator, cog_i18n from redbot.core.i18n import Translator, cog_i18n
@ -317,7 +317,7 @@ class CustomCommands(commands.Cog):
""" """
Searches through custom commands, according to the query. Searches through custom commands, according to the query.
Uses fuzzywuzzy searching to find close matches. Uses fuzzy searching to find close matches.
**Arguments:** **Arguments:**
@ -326,10 +326,10 @@ class CustomCommands(commands.Cog):
cc_commands = await CommandObj.get_commands(self.config.guild(ctx.guild)) cc_commands = await CommandObj.get_commands(self.config.guild(ctx.guild))
extracted = process.extract(query, list(cc_commands.keys())) extracted = process.extract(query, list(cc_commands.keys()))
accepted = [] accepted = []
for entry in extracted: for key, score, __ in extracted:
if entry[1] > 60: if score > 60:
# Match was decently strong # Match was decently strong
accepted.append((entry[0], cc_commands[entry[0]])) accepted.append((key, cc_commands[key]))
else: else:
# Match wasn't strong enough # Match wasn't strong enough
pass pass

View File

@ -1098,6 +1098,8 @@ class Red(
""" """
This should only be run once, prior to logging in to Discord REST API. This should only be run once, prior to logging in to Discord REST API.
""" """
await super()._pre_login()
await self._maybe_update_config() await self._maybe_update_config()
self.description = await self._config.description() self.description = await self._config.description()
self._color = discord.Colour(await self._config.color()) self._color = discord.Colour(await self._config.color())

View File

@ -8,7 +8,7 @@ from copy import deepcopy
from pathlib import Path from pathlib import Path
from typing import Any, Dict from typing import Any, Dict
import appdirs import platformdirs
from discord.utils import deprecated from discord.utils import deprecated
from . import commands from . import commands
@ -37,22 +37,30 @@ basic_config_default: Dict[str, Any] = {
"CORE_PATH_APPEND": "core", "CORE_PATH_APPEND": "core",
} }
appdir = appdirs.AppDirs("Red-DiscordBot") appdir = platformdirs.PlatformDirs("Red-DiscordBot")
config_dir = Path(appdir.user_config_dir) config_dir = appdir.user_config_path
_system_user = sys.platform == "linux" and 0 < os.getuid() < 1000 _system_user = sys.platform == "linux" and 0 < os.getuid() < 1000
if _system_user: if _system_user:
if Path.home().exists(): if Path.home().exists():
# We don't want to break someone just because they created home dir # 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. # But otherwise, we do want Red to use user_config_path if home dir exists.
_maybe_config_file = Path(appdir.site_data_dir) / "config.json" _maybe_config_file = appdir.site_data_path / "config.json"
if _maybe_config_file.exists(): if _maybe_config_file.exists():
config_dir = _maybe_config_file.parent config_dir = _maybe_config_file.parent
else: else:
config_dir = Path(appdir.site_data_dir) config_dir = appdir.site_data_path
config_file = config_dir / "config.json" 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(): def load_existing_config():

View File

@ -64,14 +64,20 @@ class RPC:
RPC server manager. RPC server manager.
""" """
app: web.Application
_rpc: RedRpc
_runner: web.AppRunner
def __init__(self): def __init__(self):
self._site: Optional[web.TCPSite] = None
self._started = False
async def _pre_login(self) -> None:
self.app = web.Application() self.app = web.Application()
self._rpc = RedRpc() self._rpc = RedRpc()
self.app.router.add_route("*", "/", self._rpc.handle_request) self.app.router.add_route("*", "/", self._rpc.handle_request)
self._runner = web.AppRunner(self.app) self._runner = web.AppRunner(self.app)
self._site: Optional[web.TCPSite] = None
self._started = False
async def initialize(self, port: int): async def initialize(self, port: int):
""" """
@ -134,6 +140,9 @@ class RPCMixin:
self.rpc_handlers = {} # Uppercase cog name to method 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): def register_rpc_handler(self, method):
""" """
Registers a method to act as an RPC handler if the internal RPC server is active. Registers a method to act as an RPC handler if the internal RPC server is active.

View File

@ -32,7 +32,7 @@ from typing import (
import aiohttp import aiohttp
import discord import discord
from packaging.requirements import Requirement from packaging.requirements import Requirement
from fuzzywuzzy import fuzz, process from rapidfuzz import fuzz, process
from rich.progress import ProgressColumn from rich.progress import ProgressColumn
from rich.progress_bar import ProgressBar from rich.progress_bar import ProgressBar
from red_commons.logging import VERBOSE, TRACE from red_commons.logging import VERBOSE, TRACE
@ -147,20 +147,20 @@ async def fuzzy_command_search(
return None return None
if commands is 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): elif isinstance(commands, collections.abc.AsyncIterator):
choices = {c async for c in commands} choices = {c: c.qualified_name async for c in commands}
else: 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) extracted = process.extract(term, choices, limit=5, scorer=fuzz.QRatio)
if not extracted: if not extracted:
return None return None
# Filter through the fuzzy-matched commands. # Filter through the fuzzy-matched commands.
matched_commands = [] matched_commands = []
for command, score in extracted: for __, score, command in extracted:
if score < min_score: if score < min_score:
# Since the list is in decreasing order of score, we can exit early. # Since the list is in decreasing order of score, we can exit early.
break break

View File

@ -10,7 +10,7 @@ from datetime import datetime # This clearly never leads to confusion...
from os import isatty from os import isatty
import rich import rich
from pygments.styles.monokai import MonokaiStyle from pygments.styles.monokai import MonokaiStyle # DEP-WARN
from pygments.token import ( from pygments.token import (
Comment, Comment,
Error, Error,
@ -22,16 +22,14 @@ from pygments.token import (
Token, Token,
) )
from rich._log_render import LogRender # DEP-WARN from rich._log_render import LogRender # DEP-WARN
from rich.console import render_group from rich.console import group
from rich.containers import Renderables
from rich.highlighter import NullHighlighter from rich.highlighter import NullHighlighter
from rich.logging import RichHandler from rich.logging import RichHandler
from rich.style import Style from rich.style import Style
from rich.syntax import ANSISyntaxTheme, PygmentsSyntaxTheme from rich.syntax import ANSISyntaxTheme, PygmentsSyntaxTheme # DEP-WARN
from rich.table import Table
from rich.text import Text from rich.text import Text
from rich.theme import Theme from rich.theme import Theme
from rich.traceback import PathHighlighter, Traceback from rich.traceback import PathHighlighter, Traceback # DEP-WARN
MAX_OLD_LOGS = 8 MAX_OLD_LOGS = 8
@ -151,7 +149,8 @@ class FixedMonokaiStyle(MonokaiStyle):
class RedTraceback(Traceback): class RedTraceback(Traceback):
@render_group() # DEP-WARN
@group()
def _render_stack(self, stack): def _render_stack(self, stack):
for obj in super()._render_stack.__wrapped__(self, stack): for obj in super()._render_stack.__wrapped__(self, stack):
if obj != "": if obj != "":

View File

@ -7,8 +7,10 @@ __all__ = ["rpc", "rpcmixin", "cog", "existing_func", "existing_multi_func"]
@pytest.fixture() @pytest.fixture()
def rpc(): async def rpc():
return RPC() rpc = RPC()
await rpc._pre_login()
return rpc
@pytest.fixture() @pytest.fixture()

View File

@ -1,23 +1,24 @@
aiodns
aiohttp aiohttp
aiohttp-json-rpc aiohttp-json-rpc
aiosqlite apsw
appdirs
apsw-wheels
babel babel
Brotli
click click
colorama
discord.py discord.py
fuzzywuzzy
markdown markdown
orjson
packaging packaging
platformdirs
psutil psutil
python-dateutil python-dateutil
python-Levenshtein-wheels
PyNaCl
PyYAML PyYAML
rapidfuzz
Red-Commons Red-Commons
Red-Lavalink>=0.11.0rc1 Red-Lavalink>=0.11.0rc1
rich rich
schema schema
typing_extensions
yarl
distro; sys_platform == "linux" distro; sys_platform == "linux"
uvloop; sys_platform != "win32" and platform_python_implementation == "CPython" uvloop; sys_platform != "win32" and platform_python_implementation == "CPython"

View File

@ -1,4 +1,6 @@
aiohttp==3.7.4.post0 aiodns==3.0.0
# via -r base.in
aiohttp==3.8.3
# via # via
# -r base.in # -r base.in
# aiohttp-json-rpc # aiohttp-json-rpc
@ -6,28 +8,24 @@ aiohttp==3.7.4.post0
# red-lavalink # red-lavalink
aiohttp-json-rpc==0.13.3 aiohttp-json-rpc==0.13.3
# via -r base.in # via -r base.in
aiosqlite==0.17.0 aiosignal==1.3.1
# 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
# via aiohttp # via aiohttp
attrs==21.2.0 apsw==3.40.0.0
# via aiohttp
babel==2.9.1
# via -r base.in # via -r base.in
cffi==1.14.6 async-timeout==4.0.2
# via pynacl
chardet==4.0.0
# via aiohttp # 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 # via -r base.in
colorama==0.4.4
# via
# -r base.in
# click
commonmark==0.9.1 commonmark==0.9.1
# via rich # via rich
contextlib2==21.6.0 contextlib2==21.6.0
@ -36,33 +34,41 @@ discord-py==2.1.0
# via # via
# -r base.in # -r base.in
# red-lavalink # red-lavalink
fuzzywuzzy==0.18.0 frozenlist==1.3.3
# via -r base.in # via
idna==3.2 # aiohttp
# aiosignal
idna==3.4
# via yarl # via yarl
markdown==3.3.4 importlib-metadata==5.2.0
# via markdown
markdown==3.4.1
# via -r base.in # via -r base.in
multidict==5.1.0 multidict==6.0.4
# via # via
# aiohttp # aiohttp
# yarl # yarl
orjson==3.8.3
# via -r base.in
packaging==22.0 packaging==22.0
# via -r base.in # via -r base.in
psutil==5.8.0 platformdirs==2.6.0
# via -r base.in # 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 # via cffi
pygments==2.10.0 pygments==2.13.0
# via rich # via rich
pynacl==1.4.0
# via -r base.in
python-dateutil==2.8.2 python-dateutil==2.8.2
# via -r base.in # via -r base.in
python-levenshtein-wheels==0.13.2 pytz==2022.7
# via -r base.in
pytz==2021.1
# via babel # via babel
pyyaml==5.4.1 pyyaml==6.0
# via -r base.in
rapidfuzz==2.13.7
# via -r base.in # via -r base.in
red-commons==1.0.0 red-commons==1.0.0
# via # via
@ -70,19 +76,25 @@ red-commons==1.0.0
# red-lavalink # red-lavalink
red-lavalink==0.11.0rc1 red-lavalink==0.11.0rc1
# via -r base.in # via -r base.in
rich==10.9.0 rich==12.6.0
# via -r base.in # via -r base.in
schema==0.7.4 schema==0.7.5
# via -r base.in # via -r base.in
six==1.16.0 six==1.16.0
# via python-dateutil # via python-dateutil
typing-extensions==3.10.0.2 typing-extensions==4.4.0
# via rich # via
yarl==1.6.3 # -r base.in
# rich
yarl==1.8.2
# via # via
# -r base.in # -r base.in
# aiohttp # 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 # 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 # via -r base.in

View File

@ -1,24 +1,22 @@
alabaster==0.7.12 alabaster==0.7.12
# via sphinx # via sphinx
certifi==2021.5.30 certifi==2022.12.7
# via requests # via requests
charset-normalizer==2.0.4 docutils==0.17.1
# via requests
docutils==0.16
# via # via
# sphinx # sphinx
# sphinx-rtd-theme # sphinx-rtd-theme
imagesize==1.2.0 imagesize==1.4.1
# via sphinx # via sphinx
jinja2==3.0.1 jinja2==3.1.2
# via sphinx # via sphinx
markupsafe==2.0.1 markupsafe==2.1.1
# via jinja2 # via jinja2
requests==2.26.0 requests==2.28.1
# via sphinx # via sphinx
snowballstemmer==2.1.0 snowballstemmer==2.2.0
# via sphinx # via sphinx
sphinx==4.1.2 sphinx==5.3.0
# via # via
# -r extra-doc.in # -r extra-doc.in
# sphinx-prompt # sphinx-prompt
@ -26,7 +24,7 @@ sphinx==4.1.2
# sphinxcontrib-trio # sphinxcontrib-trio
sphinx-prompt==1.5.0 sphinx-prompt==1.5.0
# via -r extra-doc.in # via -r extra-doc.in
sphinx-rtd-theme==0.5.2 sphinx-rtd-theme==1.1.1
# via -r extra-doc.in # via -r extra-doc.in
sphinxcontrib-applehelp==1.0.2 sphinxcontrib-applehelp==1.0.2
# via sphinx # via sphinx
@ -42,5 +40,5 @@ sphinxcontrib-serializinghtml==1.1.5
# via sphinx # via sphinx
sphinxcontrib-trio==1.1.2 sphinxcontrib-trio==1.1.2
# via -r extra-doc.in # via -r extra-doc.in
urllib3==1.26.6 urllib3==1.26.13
# via requests # via requests

View File

@ -1,2 +1,2 @@
asyncpg==0.24.0 asyncpg==0.27.0
# via -r extra-postgres.in # via -r extra-postgres.in

View File

@ -1,12 +1,8 @@
black==22.1.0 black==22.12.0
# via -r extra-style.in # via -r extra-style.in
mypy-extensions==0.4.3 mypy-extensions==0.4.3
# via black # via black
pathspec==0.9.0 pathspec==0.10.3
# via black # via black
regex==2021.8.28 tomli==2.0.1
# via black
toml==0.10.2
# via black
typed-ast==1.4.3
# via black # via black

View File

@ -1,33 +1,35 @@
astroid==2.7.3 astroid==2.12.13
# via pylint # via pylint
dill==0.3.6
# via pylint
exceptiongroup==1.1.0
# via pytest
iniconfig==1.1.1 iniconfig==1.1.1
# via pytest # via pytest
isort==5.9.3 isort==5.11.4
# via pylint # via pylint
lazy-object-proxy==1.6.0 lazy-object-proxy==1.8.0
# via astroid # via astroid
mccabe==0.6.1 mccabe==0.7.0
# via pylint
platformdirs==2.3.0
# via pylint # via pylint
pluggy==1.0.0 pluggy==1.0.0
# via pytest # via pytest
py==1.10.0 pylint==2.15.9
# via pytest
pylint==2.10.2
# via -r extra-test.in # via -r extra-test.in
pytest==6.2.5 pytest==7.2.0
# via # via
# -r extra-test.in # -r extra-test.in
# pytest-asyncio # pytest-asyncio
# pytest-mock # pytest-mock
pytest-asyncio==0.15.1 pytest-asyncio==0.20.3
# via -r extra-test.in # via -r extra-test.in
pytest-mock==3.6.1 pytest-mock==3.10.0
# via -r extra-test.in # via -r extra-test.in
toml==0.10.2 tomli==2.0.1
# via # via
# pylint # pylint
# pytest # pytest
wrapt==1.12.1 tomlkit==0.11.6
# via pylint
wrapt==1.14.1
# via astroid # via astroid

View File

@ -47,8 +47,8 @@ extras_require["all"] = extras_combined("postgres")
python_requires = ">=3.8.1" python_requires = ">=3.8.1"
if not os.getenv("TOX_RED", False) or sys.version_info < (3, 10): if not os.getenv("TOX_RED", False) or sys.version_info < (3, 12):
python_requires += ",<3.10" python_requires += ",<3.12"
# Metadata and options defined in pyproject.toml # Metadata and options defined in pyproject.toml
setup( setup(

View File

@ -65,7 +65,6 @@ ancestor_rev = "c950fc05a540dd76b944719c2a3302da2e2f3090"
descendant_rev = "fb99eb7d2d5bed514efc98fe6686b368f8425745" descendant_rev = "fb99eb7d2d5bed514efc98fe6686b368f8425745"
@pytest.mark.asyncio
@pytest.mark.parametrize( @pytest.mark.parametrize(
"maybe_ancestor_rev,descendant_rev,returncode,expected", "maybe_ancestor_rev,descendant_rev,returncode,expected",
[(ancestor_rev, descendant_rev, 0, True), (descendant_rev, ancestor_rev, 1, False)], [(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 assert ret is expected
@pytest.mark.asyncio
async def test_is_ancestor_object_raise(mocker, repo): async def test_is_ancestor_object_raise(mocker, repo):
m = _mock_run(mocker, repo, 128, b"", b"fatal: Not a valid object name invalid1") m = _mock_run(mocker, repo, 128, b"", b"fatal: Not a valid object name invalid1")
with pytest.raises(UnknownRevision): 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): async def test_is_ancestor_commit_raise(mocker, repo):
m = _mock_run( m = _mock_run(
mocker, 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): async def test_get_file_update_statuses(mocker, repo):
old_rev = "c950fc05a540dd76b944719c2a3302da2e2f3090" old_rev = "c950fc05a540dd76b944719c2a3302da2e2f3090"
new_rev = "fb99eb7d2d5bed514efc98fe6686b368f8425745" 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): async def test_is_module_modified(mocker, repo):
old_rev = "c950fc05a540dd76b944719c2a3302da2e2f3090" old_rev = "c950fc05a540dd76b944719c2a3302da2e2f3090"
new_rev = "fb99eb7d2d5bed514efc98fe6686b368f8425745" new_rev = "fb99eb7d2d5bed514efc98fe6686b368f8425745"
@ -184,7 +179,6 @@ async def test_is_module_modified(mocker, repo):
assert ret is True assert ret is True
@pytest.mark.asyncio
async def test_get_full_sha1_success(mocker, repo): async def test_get_full_sha1_success(mocker, repo):
commit = "c950fc05a540dd76b944719c2a3302da2e2f3090" commit = "c950fc05a540dd76b944719c2a3302da2e2f3090"
m = _mock_run(mocker, repo, 0, commit.encode()) m = _mock_run(mocker, repo, 0, commit.encode())
@ -196,7 +190,6 @@ async def test_get_full_sha1_success(mocker, repo):
assert ret == commit assert ret == commit
@pytest.mark.asyncio
async def test_get_full_sha1_notfound(mocker, repo): async def test_get_full_sha1_notfound(mocker, repo):
m = _mock_run(mocker, repo, 128, b"", b"fatal: Needed a single revision") m = _mock_run(mocker, repo, 128, b"", b"fatal: Needed a single revision")
with pytest.raises(UnknownRevision): 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): async def test_get_full_sha1_ambiguous(mocker, repo):
m = _mock_run( m = _mock_run(
mocker, mocker,
@ -246,7 +238,6 @@ def test_update_available_modules(repo):
) )
@pytest.mark.asyncio
async def test_checkout(mocker, repo): async def test_checkout(mocker, repo):
commit = "c950fc05a540dd76b944719c2a3302da2e2f3090" commit = "c950fc05a540dd76b944719c2a3302da2e2f3090"
m = _mock_run(mocker, repo, 0) 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): async def test_checkout_ctx_manager(mocker, repo):
commit = "c950fc05a540dd76b944719c2a3302da2e2f3090" commit = "c950fc05a540dd76b944719c2a3302da2e2f3090"
m = mocker.patch.object(repo, "_checkout", autospec=True, return_value=None) 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) m.assert_called_with(old_commit, force_checkout=False)
@pytest.mark.asyncio
async def test_checkout_await(mocker, repo): async def test_checkout_await(mocker, repo):
commit = "c950fc05a540dd76b944719c2a3302da2e2f3090" commit = "c950fc05a540dd76b944719c2a3302da2e2f3090"
m = mocker.patch.object(repo, "_checkout", autospec=True, return_value=None) 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) m.assert_called_once_with(commit, force_checkout=False)
@pytest.mark.asyncio
async def test_clone_with_branch(mocker, repo): async def test_clone_with_branch(mocker, repo):
branch = repo.branch = "dont_add_commits" branch = repo.branch = "dont_add_commits"
commit = "a0ccc2390883c85a361f5a90c72e1b07958939fa" 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): async def test_clone_without_branch(mocker, repo):
branch = "dont_add_commits" branch = "dont_add_commits"
commit = "a0ccc2390883c85a361f5a90c72e1b07958939fa" commit = "a0ccc2390883c85a361f5a90c72e1b07958939fa"
@ -318,7 +305,6 @@ async def test_clone_without_branch(mocker, repo):
) )
@pytest.mark.asyncio
async def test_update(mocker, repo): async def test_update(mocker, repo):
old_commit = repo.commit old_commit = repo.commit
new_commit = "a0ccc2390883c85a361f5a90c72e1b07958939fa" new_commit = "a0ccc2390883c85a361f5a90c72e1b07958939fa"
@ -335,7 +321,6 @@ async def test_update(mocker, repo):
# old tests # old tests
@pytest.mark.asyncio
async def test_add_repo(monkeypatch, repo_manager): async def test_add_repo(monkeypatch, repo_manager):
monkeypatch.setattr("redbot.cogs.downloader.repo_manager.Repo._run", fake_run_noprint) monkeypatch.setattr("redbot.cogs.downloader.repo_manager.Repo._run", fake_run_noprint)
monkeypatch.setattr( monkeypatch.setattr(
@ -349,7 +334,6 @@ async def test_add_repo(monkeypatch, repo_manager):
assert squid.available_modules == () assert squid.available_modules == ()
@pytest.mark.asyncio
async def test_lib_install_requirements(monkeypatch, library_installable, repo, tmpdir): 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("redbot.cogs.downloader.repo_manager.Repo._run", fake_run_noprint)
monkeypatch.setattr( monkeypatch.setattr(
@ -368,7 +352,6 @@ async def test_lib_install_requirements(monkeypatch, library_installable, repo,
assert len(failed) == 0 assert len(failed) == 0
@pytest.mark.asyncio
async def test_remove_repo(monkeypatch, repo_manager): async def test_remove_repo(monkeypatch, repo_manager):
monkeypatch.setattr("redbot.cogs.downloader.repo_manager.Repo._run", fake_run_noprint) monkeypatch.setattr("redbot.cogs.downloader.repo_manager.Repo._run", fake_run_noprint)
monkeypatch.setattr( monkeypatch.setattr(
@ -383,7 +366,6 @@ async def test_remove_repo(monkeypatch, repo_manager):
assert repo_manager.get_repo("squid") is None assert repo_manager.get_repo("squid") is None
@pytest.mark.asyncio
async def test_existing_repo(mocker, repo_manager): async def test_existing_repo(mocker, repo_manager):
repo_manager.does_repo_exist = mocker.MagicMock(return_value=True) repo_manager.does_repo_exist = mocker.MagicMock(return_value=True)

View File

@ -13,7 +13,6 @@ from redbot.pytest.downloader import (
) )
@pytest.mark.asyncio
async def test_git_clone_nobranch(git_repo, tmp_path): async def test_git_clone_nobranch(git_repo, tmp_path):
p = await git_repo._run( p = await git_repo._run(
ProcessFormatter().format( ProcessFormatter().format(
@ -25,7 +24,6 @@ async def test_git_clone_nobranch(git_repo, tmp_path):
assert p.returncode == 0 assert p.returncode == 0
@pytest.mark.asyncio
async def test_git_clone_branch(git_repo, tmp_path): async def test_git_clone_branch(git_repo, tmp_path):
p = await git_repo._run( p = await git_repo._run(
ProcessFormatter().format( ProcessFormatter().format(
@ -38,7 +36,6 @@ async def test_git_clone_branch(git_repo, tmp_path):
assert p.returncode == 0 assert p.returncode == 0
@pytest.mark.asyncio
async def test_git_clone_non_existent_branch(git_repo, tmp_path): async def test_git_clone_non_existent_branch(git_repo, tmp_path):
p = await git_repo._run( p = await git_repo._run(
ProcessFormatter().format( ProcessFormatter().format(
@ -51,7 +48,6 @@ async def test_git_clone_non_existent_branch(git_repo, tmp_path):
assert p.returncode == 128 assert p.returncode == 128
@pytest.mark.asyncio
async def test_git_clone_notgit_repo(git_repo, tmp_path): async def test_git_clone_notgit_repo(git_repo, tmp_path):
notgit_repo = tmp_path / "test_clone_folder" notgit_repo = tmp_path / "test_clone_folder"
p = await git_repo._run( p = await git_repo._run(
@ -62,7 +58,6 @@ async def test_git_clone_notgit_repo(git_repo, tmp_path):
assert p.returncode == 128 assert p.returncode == 128
@pytest.mark.asyncio
async def test_git_current_branch_master(git_repo): async def test_git_current_branch_master(git_repo):
p = await git_repo._run( p = await git_repo._run(
ProcessFormatter().format(git_repo.GIT_CURRENT_BRANCH, path=git_repo.folder_path) 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" assert p.stdout.decode().strip() == "master"
@pytest.mark.asyncio
async def test_git_current_branch_detached(git_repo): async def test_git_current_branch_detached(git_repo):
await git_repo._run( await git_repo._run(
ProcessFormatter().format( 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" 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): async def test_git_current_commit_on_branch(git_repo):
# HEAD on dont_add_commits (a0ccc2390883c85a361f5a90c72e1b07958939fa) # HEAD on dont_add_commits (a0ccc2390883c85a361f5a90c72e1b07958939fa)
# setup # setup
@ -105,7 +98,6 @@ async def test_git_current_commit_on_branch(git_repo):
assert p.stdout.decode().strip() == "a0ccc2390883c85a361f5a90c72e1b07958939fa" assert p.stdout.decode().strip() == "a0ccc2390883c85a361f5a90c72e1b07958939fa"
@pytest.mark.asyncio
async def test_git_current_commit_detached(git_repo): async def test_git_current_commit_detached(git_repo):
# detached HEAD state (c950fc05a540dd76b944719c2a3302da2e2f3090) # detached HEAD state (c950fc05a540dd76b944719c2a3302da2e2f3090)
await git_repo._run( await git_repo._run(
@ -122,7 +114,6 @@ async def test_git_current_commit_detached(git_repo):
assert p.stdout.decode().strip() == "c950fc05a540dd76b944719c2a3302da2e2f3090" assert p.stdout.decode().strip() == "c950fc05a540dd76b944719c2a3302da2e2f3090"
@pytest.mark.asyncio
async def test_git_latest_commit(git_repo): async def test_git_latest_commit(git_repo):
# HEAD on dont_add_commits (a0ccc2390883c85a361f5a90c72e1b07958939fa) # HEAD on dont_add_commits (a0ccc2390883c85a361f5a90c72e1b07958939fa)
p = await git_repo._run( p = await git_repo._run(
@ -134,7 +125,6 @@ async def test_git_latest_commit(git_repo):
assert p.stdout.decode().strip() == "a0ccc2390883c85a361f5a90c72e1b07958939fa" assert p.stdout.decode().strip() == "a0ccc2390883c85a361f5a90c72e1b07958939fa"
@pytest.mark.asyncio
async def test_git_hard_reset(cloned_git_repo, tmp_path): async def test_git_hard_reset(cloned_git_repo, tmp_path):
staged_file = cloned_git_repo.folder_path / "staged_file.txt" staged_file = cloned_git_repo.folder_path / "staged_file.txt"
staged_file.touch() staged_file.touch()
@ -150,7 +140,6 @@ async def test_git_hard_reset(cloned_git_repo, tmp_path):
assert staged_file.exists() is False assert staged_file.exists() is False
@pytest.mark.asyncio
async def test_git_pull(git_repo_with_remote, tmp_path): async def test_git_pull(git_repo_with_remote, tmp_path):
# setup # setup
staged_file = Path(git_repo_with_remote.url) / "staged_file.txt" 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() assert (git_repo_with_remote.folder_path / "staged_file.txt").exists()
@pytest.mark.asyncio
async def test_git_diff_file_status(git_repo): async def test_git_diff_file_status(git_repo):
p = await git_repo._run( p = await git_repo._run(
ProcessFormatter().format( 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 # 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): async def test_git_discover_remote_url(cloned_git_repo, tmp_path):
p = await cloned_git_repo._run( p = await cloned_git_repo._run(
ProcessFormatter().format( 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 assert p.stdout.decode().strip() == cloned_git_repo.url
@pytest.mark.asyncio
async def test_git_checkout_detached_head(git_repo): async def test_git_checkout_detached_head(git_repo):
p = await git_repo._run( p = await git_repo._run(
ProcessFormatter().format( ProcessFormatter().format(
@ -218,7 +204,6 @@ async def test_git_checkout_detached_head(git_repo):
assert p.returncode == 0 assert p.returncode == 0
@pytest.mark.asyncio
async def test_git_checkout_branch(git_repo): async def test_git_checkout_branch(git_repo):
p = await git_repo._run( p = await git_repo._run(
ProcessFormatter().format( ProcessFormatter().format(
@ -228,7 +213,6 @@ async def test_git_checkout_branch(git_repo):
assert p.returncode == 0 assert p.returncode == 0
@pytest.mark.asyncio
async def test_git_checkout_non_existent_branch(git_repo): async def test_git_checkout_non_existent_branch(git_repo):
p = await git_repo._run( p = await git_repo._run(
ProcessFormatter().format( ProcessFormatter().format(
@ -238,7 +222,6 @@ async def test_git_checkout_non_existent_branch(git_repo):
assert p.returncode == 1 assert p.returncode == 1
@pytest.mark.asyncio
async def test_git_get_full_sha1_from_branch_name(git_repo): async def test_git_get_full_sha1_from_branch_name(git_repo):
p = await git_repo._run( p = await git_repo._run(
ProcessFormatter().format( ProcessFormatter().format(
@ -249,7 +232,6 @@ async def test_git_get_full_sha1_from_branch_name(git_repo):
assert p.stdout.decode().strip() == "a0ccc2390883c85a361f5a90c72e1b07958939fa" assert p.stdout.decode().strip() == "a0ccc2390883c85a361f5a90c72e1b07958939fa"
@pytest.mark.asyncio
async def test_git_get_full_sha1_from_full_hash(git_repo): async def test_git_get_full_sha1_from_full_hash(git_repo):
p = await git_repo._run( p = await git_repo._run(
ProcessFormatter().format( ProcessFormatter().format(
@ -262,7 +244,6 @@ async def test_git_get_full_sha1_from_full_hash(git_repo):
assert p.stdout.decode().strip() == "c950fc05a540dd76b944719c2a3302da2e2f3090" assert p.stdout.decode().strip() == "c950fc05a540dd76b944719c2a3302da2e2f3090"
@pytest.mark.asyncio
async def test_git_get_full_sha1_from_short_hash(git_repo): async def test_git_get_full_sha1_from_short_hash(git_repo):
p = await git_repo._run( p = await git_repo._run(
ProcessFormatter().format( ProcessFormatter().format(
@ -273,7 +254,6 @@ async def test_git_get_full_sha1_from_short_hash(git_repo):
assert p.stdout.decode().strip() == "c950fc05a540dd76b944719c2a3302da2e2f3090" assert p.stdout.decode().strip() == "c950fc05a540dd76b944719c2a3302da2e2f3090"
@pytest.mark.asyncio
async def test_git_get_full_sha1_from_too_short_hash(git_repo): async def test_git_get_full_sha1_from_too_short_hash(git_repo):
p = await git_repo._run( p = await git_repo._run(
ProcessFormatter().format(git_repo.GIT_GET_FULL_SHA1, path=git_repo.folder_path, rev="c95") 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" 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): async def test_git_get_full_sha1_from_lightweight_tag(git_repo):
p = await git_repo._run( p = await git_repo._run(
ProcessFormatter().format( ProcessFormatter().format(
@ -293,7 +272,6 @@ async def test_git_get_full_sha1_from_lightweight_tag(git_repo):
assert p.stdout.decode().strip() == "fb99eb7d2d5bed514efc98fe6686b368f8425745" assert p.stdout.decode().strip() == "fb99eb7d2d5bed514efc98fe6686b368f8425745"
@pytest.mark.asyncio
async def test_git_get_full_sha1_from_annotated_tag(git_repo): async def test_git_get_full_sha1_from_annotated_tag(git_repo):
p = await git_repo._run( p = await git_repo._run(
ProcessFormatter().format( ProcessFormatter().format(
@ -304,7 +282,6 @@ async def test_git_get_full_sha1_from_annotated_tag(git_repo):
assert p.stdout.decode().strip() == "a7120330cc179396914e0d6af80cfa282adc124b" assert p.stdout.decode().strip() == "a7120330cc179396914e0d6af80cfa282adc124b"
@pytest.mark.asyncio
async def test_git_get_full_sha1_from_invalid_ref(git_repo): async def test_git_get_full_sha1_from_invalid_ref(git_repo):
p = await git_repo._run( p = await git_repo._run(
ProcessFormatter().format( ProcessFormatter().format(
@ -318,7 +295,6 @@ async def test_git_get_full_sha1_from_invalid_ref(git_repo):
@pytest.mark.skipif( @pytest.mark.skipif(
GIT_VERSION < (2, 31), reason="This is test for output from Git 2.31 and newer." 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): async def test_git_get_full_sha1_from_ambiguous_commits(git_repo):
# 2 ambiguous refs: # 2 ambiguous refs:
# branch ambiguous_1 - 95da0b576271cb5bee5f3e075074c03ee05fed05 # branch ambiguous_1 - 95da0b576271cb5bee5f3e075074c03ee05fed05
@ -341,7 +317,6 @@ async def test_git_get_full_sha1_from_ambiguous_commits(git_repo):
@pytest.mark.skipif( @pytest.mark.skipif(
GIT_VERSION < (2, 36), reason="This is test for output from Git 2.36 and newer." 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): async def test_git_get_full_sha1_from_ambiguous_tag_and_commit(git_repo):
# 2 ambiguous refs: # 2 ambiguous refs:
# branch ambiguous_with_tag - c6f0e5ec04d99bdf8c6c78ff20d66d286eecb3ea # 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( @pytest.mark.skipif(
not ((2, 31) <= GIT_VERSION < (2, 36)), reason="This is test for output from Git >=2.31,<2.36." 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): async def test_git_get_full_sha1_from_ambiguous_tag_and_commit_pre_2_36(git_repo):
# 2 ambiguous refs: # 2 ambiguous refs:
# branch ambiguous_with_tag - c6f0e5ec04d99bdf8c6c78ff20d66d286eecb3ea # 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( @pytest.mark.skipif(
GIT_VERSION >= (2, 31), reason="This is test for output from Git older than 2.31." 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): async def test_git_get_full_sha1_from_ambiguous_commits_pre_2_31(git_repo):
# 2 ambiguous refs: # 2 ambiguous refs:
# branch ambiguous_1 - 95da0b576271cb5bee5f3e075074c03ee05fed05 # 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( @pytest.mark.skipif(
GIT_VERSION >= (2, 31), reason="This is test for output from Git older than 2.31." 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): async def test_git_get_full_sha1_from_ambiguous_tag_and_commit_pre_2_31(git_repo):
# 2 ambiguous refs: # 2 ambiguous refs:
# branch ambiguous_with_tag - c6f0e5ec04d99bdf8c6c78ff20d66d286eecb3ea # 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): async def test_git_is_ancestor_true(git_repo):
p = await git_repo._run( p = await git_repo._run(
ProcessFormatter().format( ProcessFormatter().format(
@ -443,7 +414,6 @@ async def test_git_is_ancestor_true(git_repo):
assert p.returncode == 0 assert p.returncode == 0
@pytest.mark.asyncio
async def test_git_is_ancestor_false(git_repo): async def test_git_is_ancestor_false(git_repo):
p = await git_repo._run( p = await git_repo._run(
ProcessFormatter().format( ProcessFormatter().format(
@ -456,7 +426,6 @@ async def test_git_is_ancestor_false(git_repo):
assert p.returncode == 1 assert p.returncode == 1
@pytest.mark.asyncio
async def test_git_is_ancestor_invalid_object(git_repo): async def test_git_is_ancestor_invalid_object(git_repo):
p = await git_repo._run( p = await git_repo._run(
ProcessFormatter().format( 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" 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): async def test_git_is_ancestor_invalid_commit(git_repo):
p = await git_repo._run( p = await git_repo._run(
ProcessFormatter().format( 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): async def test_git_check_if_module_exists_true(git_repo):
p = await git_repo._run( p = await git_repo._run(
ProcessFormatter().format( ProcessFormatter().format(
@ -502,7 +469,6 @@ async def test_git_check_if_module_exists_true(git_repo):
@pytest.mark.skipif( @pytest.mark.skipif(
GIT_VERSION < (2, 36), reason="This is test for output from Git 2.36 and newer." 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): async def test_git_check_if_module_exists_false(git_repo):
p = await git_repo._run( p = await git_repo._run(
ProcessFormatter().format( ProcessFormatter().format(
@ -521,7 +487,6 @@ async def test_git_check_if_module_exists_false(git_repo):
@pytest.mark.skipif( @pytest.mark.skipif(
GIT_VERSION >= (2, 36), reason="This is test for output from Git older than 2.31." 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): async def test_git_check_if_module_exists_false_pre_2_36(git_repo):
p = await git_repo._run( p = await git_repo._run(
ProcessFormatter().format( 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): async def test_git_find_last_occurrence_existent(git_repo):
p = await git_repo._run( p = await git_repo._run(
ProcessFormatter().format( ProcessFormatter().format(
@ -552,7 +516,6 @@ async def test_git_find_last_occurrence_existent(git_repo):
assert p.stdout.decode().strip() == "a7120330cc179396914e0d6af80cfa282adc124b" assert p.stdout.decode().strip() == "a7120330cc179396914e0d6af80cfa282adc124b"
@pytest.mark.asyncio
async def test_git_find_last_occurrence_non_existent(git_repo): async def test_git_find_last_occurrence_non_existent(git_repo):
p = await git_repo._run( p = await git_repo._run(
ProcessFormatter().format( ProcessFormatter().format(

View File

@ -7,12 +7,10 @@ def test_is_valid_alias_name(alias):
assert alias.is_valid_alias_name("not valid name") is False assert alias.is_valid_alias_name("not valid name") is False
@pytest.mark.asyncio
async def test_empty_guild_aliases(alias, empty_guild): async def test_empty_guild_aliases(alias, empty_guild):
assert list(await alias._aliases.get_guild_aliases(empty_guild)) == [] assert list(await alias._aliases.get_guild_aliases(empty_guild)) == []
@pytest.mark.asyncio
async def test_empty_global_aliases(alias): async def test_empty_global_aliases(alias):
assert list(await alias._aliases.get_global_aliases()) == [] 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) await alias._aliases.add_alias(ctx, "test_global", "ping", global_=True)
@pytest.mark.asyncio
async def test_add_guild_alias(alias, ctx): async def test_add_guild_alias(alias, ctx):
await create_test_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" assert alias_obj.name == "test"
@pytest.mark.asyncio
async def test_delete_guild_alias(alias, ctx): async def test_delete_guild_alias(alias, ctx):
await create_test_guild_alias(alias, ctx) await create_test_guild_alias(alias, ctx)
alias_obj = await alias._aliases.get_alias(ctx.guild, "test") 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 assert alias_obj is None
@pytest.mark.asyncio
async def test_add_global_alias(alias, ctx): async def test_add_global_alias(alias, ctx):
await create_test_global_alias(alias, ctx) await create_test_global_alias(alias, ctx)
alias_obj = await alias._aliases.get_alias(ctx.guild, "test_global") 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" assert alias_obj.name == "test_global"
@pytest.mark.asyncio
async def test_delete_global_alias(alias, ctx): async def test_delete_global_alias(alias, ctx):
await create_test_global_alias(alias, ctx) await create_test_global_alias(alias, ctx)
alias_obj = await alias._aliases.get_alias(ctx.guild, "test_global") alias_obj = await alias._aliases.get_alias(ctx.guild, "test_global")

View File

@ -2,7 +2,6 @@ import pytest
from redbot.pytest.economy import * from redbot.pytest.economy import *
@pytest.mark.asyncio
async def test_bank_register(bank, ctx): async def test_bank_register(bank, ctx):
default_bal = await bank.get_default_balance(ctx.guild) default_bal = await bank.get_default_balance(ctx.guild)
assert default_bal == (await bank.get_account(ctx.author)).balance 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) await bank.set_balance(member, balance)
@pytest.mark.asyncio
async def test_bank_transfer(bank, member_factory): async def test_bank_transfer(bank, member_factory):
mbr1 = member_factory.get() mbr1 = member_factory.get()
mbr2 = member_factory.get() mbr2 = member_factory.get()
@ -28,7 +26,6 @@ async def test_bank_transfer(bank, member_factory):
assert bal2 + 50 == newbal2 assert bal2 + 50 == newbal2
@pytest.mark.asyncio
async def test_bank_set(bank, member_factory): async def test_bank_set(bank, member_factory):
mbr = member_factory.get() mbr = member_factory.get()
await bank.set_balance(mbr, 250) await bank.set_balance(mbr, 250)
@ -36,7 +33,6 @@ async def test_bank_set(bank, member_factory):
assert acc.balance == 250 assert acc.balance == 250
@pytest.mark.asyncio
async def test_bank_can_spend(bank, member_factory): async def test_bank_can_spend(bank, member_factory):
mbr = member_factory.get() mbr = member_factory.get()
canspend = await bank.can_spend(mbr, 50) canspend = await bank.can_spend(mbr, 50)
@ -47,7 +43,6 @@ async def test_bank_can_spend(bank, member_factory):
assert canspendnow assert canspendnow
@pytest.mark.asyncio
async def test_set_bank_name(bank, guild_factory): async def test_set_bank_name(bank, guild_factory):
guild = guild_factory.get() guild = guild_factory.get()
await bank.set_bank_name("Test Bank", guild) 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" assert name == "Test Bank"
@pytest.mark.asyncio
async def test_set_currency_name(bank, guild_factory): async def test_set_currency_name(bank, guild_factory):
guild = guild_factory.get() guild = guild_factory.get()
await bank.set_currency_name("Coins", guild) await bank.set_currency_name("Coins", guild)
@ -63,7 +57,6 @@ async def test_set_currency_name(bank, guild_factory):
assert name == "Coins" assert name == "Coins"
@pytest.mark.asyncio
async def test_set_default_balance(bank, guild_factory): async def test_set_default_balance(bank, guild_factory):
guild = guild_factory.get() guild = guild_factory.get()
await bank.set_default_balance(500, guild) await bank.set_default_balance(500, guild)
@ -71,7 +64,6 @@ async def test_set_default_balance(bank, guild_factory):
assert default_bal == 500 assert default_bal == 500
@pytest.mark.asyncio
async def test_nonint_transaction_amount(bank, member_factory): async def test_nonint_transaction_amount(bank, member_factory):
mbr1 = member_factory.get() mbr1 = member_factory.get()
mbr2 = member_factory.get() mbr2 = member_factory.get()

View File

@ -3,14 +3,12 @@ import pytest
from redbot.pytest.mod import * from redbot.pytest.mod import *
@pytest.mark.asyncio
async def test_modlog_register_casetype(mod): async def test_modlog_register_casetype(mod):
ct = {"name": "ban", "default_setting": True, "image": ":hammer:", "case_str": "Ban"} ct = {"name": "ban", "default_setting": True, "image": ":hammer:", "case_str": "Ban"}
casetype = await mod.register_casetype(**ct) casetype = await mod.register_casetype(**ct)
assert casetype is not None assert casetype is not None
@pytest.mark.asyncio
async def test_modlog_case_create(mod, ctx, member_factory): async def test_modlog_case_create(mod, ctx, member_factory):
from datetime import datetime, timezone 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()) assert case.created_at == int(created_at.timestamp())
@pytest.mark.asyncio
async def test_modlog_set_modlog_channel(mod, ctx): async def test_modlog_set_modlog_channel(mod, ctx):
await mod.set_modlog_channel(ctx.guild, ctx.channel) await mod.set_modlog_channel(ctx.guild, ctx.channel)
assert await mod.get_modlog_channel(ctx.guild) == ctx.channel.id assert await mod.get_modlog_channel(ctx.guild) == ctx.channel.id

View File

@ -7,20 +7,17 @@ from redbot.core import cog_manager
@pytest.mark.skip @pytest.mark.skip
@pytest.mark.asyncio
async def test_ensure_cogs_in_paths(cog_mgr, default_dir): async def test_ensure_cogs_in_paths(cog_mgr, default_dir):
cogs_dir = default_dir / "redbot" / "cogs" cogs_dir = default_dir / "redbot" / "cogs"
assert cogs_dir in await cog_mgr.paths() assert cogs_dir in await cog_mgr.paths()
@pytest.mark.asyncio
async def test_install_path_set(cog_mgr: cog_manager.CogManager, tmpdir): async def test_install_path_set(cog_mgr: cog_manager.CogManager, tmpdir):
path = Path(str(tmpdir)) path = Path(str(tmpdir))
await cog_mgr.set_install_path(path) await cog_mgr.set_install_path(path)
assert await cog_mgr.install_path() == path assert await cog_mgr.install_path() == path
@pytest.mark.asyncio
async def test_install_path_set_bad(cog_mgr): async def test_install_path_set_bad(cog_mgr):
path = Path("something") path = Path("something")
@ -28,14 +25,12 @@ async def test_install_path_set_bad(cog_mgr):
await cog_mgr.set_install_path(path) await cog_mgr.set_install_path(path)
@pytest.mark.asyncio
async def test_add_path(cog_mgr, tmpdir): async def test_add_path(cog_mgr, tmpdir):
path = Path(str(tmpdir)) path = Path(str(tmpdir))
await cog_mgr.add_path(path) await cog_mgr.add_path(path)
assert path in await cog_mgr.paths() assert path in await cog_mgr.paths()
@pytest.mark.asyncio
async def test_add_path_already_install_path(cog_mgr, tmpdir): async def test_add_path_already_install_path(cog_mgr, tmpdir):
path = Path(str(tmpdir)) path = Path(str(tmpdir))
await cog_mgr.set_install_path(path) 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) await cog_mgr.add_path(path)
@pytest.mark.asyncio
async def test_remove_path(cog_mgr, tmpdir): async def test_remove_path(cog_mgr, tmpdir):
path = Path(str(tmpdir)) path = Path(str(tmpdir))
await cog_mgr.add_path(path) await cog_mgr.add_path(path)

View File

@ -5,7 +5,6 @@ from collections import Counter
# region Register Tests # region Register Tests
@pytest.mark.asyncio
async def test_config_register_global(config): async def test_config_register_global(config):
config.register_global(enabled=False) config.register_global(enabled=False)
assert config.defaults["GLOBAL"]["enabled"] is 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}) config.register_global(**{"invalid var name": True})
@pytest.mark.asyncio
async def test_config_register_guild(config, empty_guild): async def test_config_register_guild(config, empty_guild):
config.register_guild(enabled=False, some_list=[], some_dict={}) config.register_guild(enabled=False, some_list=[], some_dict={})
assert config.defaults[config.GUILD]["enabled"] is False 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() == {} assert await config.guild(empty_guild).some_dict() == {}
@pytest.mark.asyncio
async def test_config_register_channel(config, empty_channel): async def test_config_register_channel(config, empty_channel):
config.register_channel(enabled=False) config.register_channel(enabled=False)
assert config.defaults[config.CHANNEL]["enabled"] is False assert config.defaults[config.CHANNEL]["enabled"] is False
assert await config.channel(empty_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): async def test_config_register_role(config, empty_role):
config.register_role(enabled=False) config.register_role(enabled=False)
assert config.defaults[config.ROLE]["enabled"] is False assert config.defaults[config.ROLE]["enabled"] is False
assert await config.role(empty_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): async def test_config_register_member(config, empty_member):
config.register_member(some_number=-1) config.register_member(some_number=-1)
assert config.defaults[config.MEMBER]["some_number"] == -1 assert config.defaults[config.MEMBER]["some_number"] == -1
assert await config.member(empty_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): async def test_config_register_user(config, empty_user):
config.register_user(some_value=None) config.register_user(some_value=None)
assert config.defaults[config.USER]["some_value"] is None assert config.defaults[config.USER]["some_value"] is None
assert await config.user(empty_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): async def test_config_force_register_global(config_fr):
with pytest.raises(AttributeError): with pytest.raises(AttributeError):
await config_fr.enabled() await config_fr.enabled()
@ -70,13 +63,11 @@ async def test_config_force_register_global(config_fr):
# Test nested registration # Test nested registration
@pytest.mark.asyncio
async def test_nested_registration(config): async def test_nested_registration(config):
config.register_global(foo__bar__baz=False) config.register_global(foo__bar__baz=False)
assert await config.foo.bar.baz() is False assert await config.foo.bar.baz() is False
@pytest.mark.asyncio
async def test_nested_registration_asdict(config): async def test_nested_registration_asdict(config):
defaults = {"bar": {"baz": False}} defaults = {"bar": {"baz": False}}
config.register_global(foo=defaults) config.register_global(foo=defaults)
@ -84,7 +75,6 @@ async def test_nested_registration_asdict(config):
assert await config.foo.bar.baz() is False assert await config.foo.bar.baz() is False
@pytest.mark.asyncio
async def test_nested_registration_and_changing(config): async def test_nested_registration_and_changing(config):
defaults = {"bar": {"baz": False}} defaults = {"bar": {"baz": False}}
config.register_global(foo=defaults) config.register_global(foo=defaults)
@ -95,7 +85,6 @@ async def test_nested_registration_and_changing(config):
await config.foo.set(True) await config.foo.set(True)
@pytest.mark.asyncio
async def test_doubleset_default(config): async def test_doubleset_default(config):
config.register_global(foo=True) config.register_global(foo=True)
config.register_global(foo=False) config.register_global(foo=False)
@ -103,7 +92,6 @@ async def test_doubleset_default(config):
assert await config.foo() is False assert await config.foo() is False
@pytest.mark.asyncio
async def test_nested_registration_multidict(config): async def test_nested_registration_multidict(config):
defaults = {"foo": {"bar": {"baz": True}}, "blah": True} defaults = {"foo": {"bar": {"baz": True}}, "blah": True}
config.register_global(**defaults) config.register_global(**defaults)
@ -118,7 +106,6 @@ def test_nested_group_value_badreg(config):
config.register_global(foo__bar=False) config.register_global(foo__bar=False)
@pytest.mark.asyncio
async def test_nested_toplevel_reg(config): async def test_nested_toplevel_reg(config):
defaults = {"bar": True, "baz": False} defaults = {"bar": True, "baz": False}
config.register_global(foo=defaults) config.register_global(foo=defaults)
@ -127,7 +114,6 @@ async def test_nested_toplevel_reg(config):
assert await config.foo.baz() is False assert await config.foo.baz() is False
@pytest.mark.asyncio
async def test_nested_overlapping(config): async def test_nested_overlapping(config):
config.register_global(foo__bar=True) config.register_global(foo__bar=True)
config.register_global(foo__baz=False) config.register_global(foo__baz=False)
@ -136,7 +122,6 @@ async def test_nested_overlapping(config):
assert await config.foo.baz() is False assert await config.foo.baz() is False
@pytest.mark.asyncio
async def test_nesting_nofr(config): async def test_nesting_nofr(config):
config.register_global(foo={}) config.register_global(foo={})
assert await config.foo.bar() is None assert await config.foo.bar() is None
@ -144,38 +129,31 @@ async def test_nesting_nofr(config):
# region Default Value Overrides # region Default Value Overrides
@pytest.mark.asyncio
async def test_global_default_override(config): async def test_global_default_override(config):
assert await config.enabled(True) is True assert await config.enabled(True) is True
@pytest.mark.asyncio
async def test_global_default_nofr(config): async def test_global_default_nofr(config):
assert await config.nofr() is None assert await config.nofr() is None
assert await config.nofr(True) is True assert await config.nofr(True) is True
@pytest.mark.asyncio
async def test_guild_default_override(config, empty_guild): async def test_guild_default_override(config, empty_guild):
assert await config.guild(empty_guild).enabled(True) is True assert await config.guild(empty_guild).enabled(True) is True
@pytest.mark.asyncio
async def test_channel_default_override(config, empty_channel): async def test_channel_default_override(config, empty_channel):
assert await config.channel(empty_channel).enabled(True) is True assert await config.channel(empty_channel).enabled(True) is True
@pytest.mark.asyncio
async def test_role_default_override(config, empty_role): async def test_role_default_override(config, empty_role):
assert await config.role(empty_role).enabled(True) is True assert await config.role(empty_role).enabled(True) is True
@pytest.mark.asyncio
async def test_member_default_override(config, empty_member): async def test_member_default_override(config, empty_member):
assert await config.member(empty_member).enabled(True) is True assert await config.member(empty_member).enabled(True) is True
@pytest.mark.asyncio
async def test_user_default_override(config, empty_user): async def test_user_default_override(config, empty_user):
assert await config.user(empty_user).some_value(True) is True 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 # region Setting Values
@pytest.mark.asyncio
async def test_set_global(config): async def test_set_global(config):
await config.enabled.set(True) await config.enabled.set(True)
assert await config.enabled() is True assert await config.enabled() is True
@pytest.mark.asyncio
async def test_set_guild(config, empty_guild): async def test_set_guild(config, empty_guild):
await config.guild(empty_guild).enabled.set(True) await config.guild(empty_guild).enabled.set(True)
assert await config.guild(empty_guild).enabled() is 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 assert await config.guild(empty_guild).some_list() == curr_list
@pytest.mark.asyncio
async def test_set_channel(config, empty_channel): async def test_set_channel(config, empty_channel):
await config.channel(empty_channel).enabled.set(True) await config.channel(empty_channel).enabled.set(True)
assert await config.channel(empty_channel).enabled() is True assert await config.channel(empty_channel).enabled() is True
@pytest.mark.asyncio
async def test_set_channel_no_register(config, empty_channel): async def test_set_channel_no_register(config, empty_channel):
await config.channel(empty_channel).no_register.set(True) await config.channel(empty_channel).no_register.set(True)
assert await config.channel(empty_channel).no_register() is 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 # Dynamic attribute testing
@pytest.mark.asyncio
async def test_set_dynamic_attr(config): async def test_set_dynamic_attr(config):
await config.set_raw("foobar", value=True) await config.set_raw("foobar", value=True)
assert await config.foobar() is True assert await config.foobar() is True
@pytest.mark.asyncio
async def test_clear_dynamic_attr(config): async def test_clear_dynamic_attr(config):
await config.foo.set(True) await config.foo.set(True)
await config.clear_raw("foo") await config.clear_raw("foo")
@ -235,13 +207,11 @@ async def test_clear_dynamic_attr(config):
await config.get_raw("foo") await config.get_raw("foo")
@pytest.mark.asyncio
async def test_get_dynamic_attr(config): async def test_get_dynamic_attr(config):
assert await config.get_raw("foobaz", default=True) is True assert await config.get_raw("foobaz", default=True) is True
# Member Group testing # Member Group testing
@pytest.mark.asyncio
async def test_membergroup_allguilds(config, empty_member): async def test_membergroup_allguilds(config, empty_member):
await config.member(empty_member).foo.set(False) 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 assert empty_member.guild.id in all_servers
@pytest.mark.asyncio
async def test_membergroup_allmembers(config, empty_member): async def test_membergroup_allmembers(config, empty_member):
await config.member(empty_member).foo.set(False) await config.member(empty_member).foo.set(False)
@ -258,7 +227,6 @@ async def test_membergroup_allmembers(config, empty_member):
# Clearing testing # Clearing testing
@pytest.mark.asyncio
async def test_global_clear(config): async def test_global_clear(config):
config.register_global(foo=True, bar=False) config.register_global(foo=True, bar=False)
@ -274,7 +242,6 @@ async def test_global_clear(config):
assert await config.bar() is False assert await config.bar() is False
@pytest.mark.asyncio
async def test_member_clear(config, member_factory): async def test_member_clear(config, member_factory):
config.register_member(foo=True) 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 assert await config.member(m2).foo() is False
@pytest.mark.asyncio
async def test_member_clear_all(config, member_factory): async def test_member_clear_all(config, member_factory):
server_ids = [] server_ids = []
for _ in range(5): for _ in range(5):
@ -309,7 +275,6 @@ async def test_member_clear_all(config, member_factory):
assert len(await config.all_members()) == 0 assert len(await config.all_members()) == 0
@pytest.mark.asyncio
async def test_clear_all(config): async def test_clear_all(config):
await config.foo.set(True) await config.foo.set(True)
assert await config.foo() is True assert await config.foo() is True
@ -319,7 +284,6 @@ async def test_clear_all(config):
await config.get_raw("foo") await config.get_raw("foo")
@pytest.mark.asyncio
async def test_clear_value(config): async def test_clear_value(config):
await config.foo.set(True) await config.foo.set(True)
await config.foo.clear() await config.foo.clear()
@ -329,7 +293,6 @@ async def test_clear_value(config):
# Get All testing # Get All testing
@pytest.mark.asyncio
async def test_user_get_all_from_kind(config, user_factory): async def test_user_get_all_from_kind(config, user_factory):
config.register_user(foo=False, bar=True) config.register_user(foo=False, bar=True)
for _ in range(5): for _ in range(5):
@ -345,7 +308,6 @@ async def test_user_get_all_from_kind(config, user_factory):
assert v["bar"] is True assert v["bar"] is True
@pytest.mark.asyncio
async def test_user_getalldata(config, user_factory): async def test_user_getalldata(config, user_factory):
user = user_factory.get() user = user_factory.get()
config.register_user(foo=True, bar=False) 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 assert config.user(user).defaults["foo"] is True
@pytest.mark.asyncio
async def test_value_ctxmgr(config): async def test_value_ctxmgr(config):
config.register_global(foo_list=[]) config.register_global(foo_list=[])
@ -371,7 +332,6 @@ async def test_value_ctxmgr(config):
assert "foo" in foo_list assert "foo" in foo_list
@pytest.mark.asyncio
async def test_value_ctxmgr_saves(config): async def test_value_ctxmgr_saves(config):
config.register_global(bar_list=[]) config.register_global(bar_list=[])
@ -387,7 +347,6 @@ async def test_value_ctxmgr_saves(config):
assert "bar" in bar_list assert "bar" in bar_list
@pytest.mark.asyncio
async def test_value_ctxmgr_immutable(config): async def test_value_ctxmgr_immutable(config):
config.register_global(foo=True) config.register_global(foo=True)
@ -399,7 +358,6 @@ async def test_value_ctxmgr_immutable(config):
assert foo is True assert foo is True
@pytest.mark.asyncio
async def test_ctxmgr_no_shared_default(config, member_factory): async def test_ctxmgr_no_shared_default(config, member_factory):
config.register_member(foo=[]) config.register_member(foo=[])
m1 = member_factory.get() 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() assert 1 not in await config.member(m2).foo()
@pytest.mark.asyncio
async def test_ctxmgr_no_unnecessary_write(config): async def test_ctxmgr_no_unnecessary_write(config):
config.register_global(foo=[]) config.register_global(foo=[])
foo_value_obj = config.foo foo_value_obj = config.foo
@ -421,7 +378,6 @@ async def test_ctxmgr_no_unnecessary_write(config):
set_method.assert_not_called() set_method.assert_not_called()
@pytest.mark.asyncio
async def test_get_then_mutate(config): async def test_get_then_mutate(config):
"""Tests that mutating an object after getting it as a value doesn't mutate the data store.""" """Tests that mutating an object after getting it as a value doesn't mutate the data store."""
config.register_global(list1=[]) config.register_global(list1=[])
@ -432,7 +388,6 @@ async def test_get_then_mutate(config):
assert "foo" not in list1 assert "foo" not in list1
@pytest.mark.asyncio
async def test_set_then_mutate(config): async def test_set_then_mutate(config):
"""Tests that mutating an object after setting it as a value doesn't mutate the data store.""" """Tests that mutating an object after setting it as a value doesn't mutate the data store."""
config.register_global(list1=[]) config.register_global(list1=[])
@ -443,14 +398,12 @@ async def test_set_then_mutate(config):
assert "foo" not in list1 assert "foo" not in list1
@pytest.mark.asyncio
async def test_call_group_fills_defaults(config): async def test_call_group_fills_defaults(config):
config.register_global(subgroup={"foo": True}) config.register_global(subgroup={"foo": True})
subgroup = await config.subgroup() subgroup = await config.subgroup()
assert "foo" in subgroup assert "foo" in subgroup
@pytest.mark.asyncio
async def test_group_call_ctxmgr_writes(config): async def test_group_call_ctxmgr_writes(config):
config.register_global(subgroup={"foo": True}) config.register_global(subgroup={"foo": True})
async with config.subgroup() as subgroup: async with config.subgroup() as subgroup:
@ -460,7 +413,6 @@ async def test_group_call_ctxmgr_writes(config):
assert subgroup == {"foo": True, "bar": False} assert subgroup == {"foo": True, "bar": False}
@pytest.mark.asyncio
async def test_all_works_as_ctxmgr(config): async def test_all_works_as_ctxmgr(config):
config.register_global(subgroup={"foo": True}) config.register_global(subgroup={"foo": True})
async with config.subgroup.all() as subgroup: 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} assert subgroup == {"foo": True, "bar": False}
@pytest.mark.asyncio
async def test_get_raw_mixes_defaults(config): async def test_get_raw_mixes_defaults(config):
config.register_global(subgroup={"foo": True}) config.register_global(subgroup={"foo": True})
await config.subgroup.set_raw("bar", value=False) 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} assert subgroup == {"foo": True, "bar": False}
@pytest.mark.asyncio
async def test_cast_str_raw(config): async def test_cast_str_raw(config):
await config.set_raw(123, 456, value=True) await config.set_raw(123, 456, value=True)
assert await config.get_raw(123, 456) is 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) await config.clear_raw("123", 456)
@pytest.mark.asyncio
async def test_cast_str_nested(config): async def test_cast_str_nested(config):
config.register_global(foo={}) config.register_global(foo={})
await config.foo.set({123: True, 456: {789: False}}) await config.foo.set({123: True, 456: {789: False}})
@ -510,7 +459,6 @@ def test_config_custom_doubleinit(config):
config.init_custom("TEST", 2) config.init_custom("TEST", 2)
@pytest.mark.asyncio
async def test_config_locks_cache(config, empty_guild): async def test_config_locks_cache(config, empty_guild):
lock1 = config.foo.get_lock() lock1 = config.foo.get_lock()
assert lock1 is 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 assert lock1 is not lock2
@pytest.mark.asyncio
async def test_config_value_atomicity(config): async def test_config_value_atomicity(config):
config.register_global(foo=[]) config.register_global(foo=[])
tasks = [] tasks = []
@ -539,7 +486,6 @@ async def test_config_value_atomicity(config):
assert len(await config.foo()) == 15 assert len(await config.foo()) == 15
@pytest.mark.asyncio
async def test_config_ctxmgr_atomicity(config): async def test_config_ctxmgr_atomicity(config):
config.register_global(foo=[]) config.register_global(foo=[])
tasks = [] tasks = []
@ -557,7 +503,6 @@ async def test_config_ctxmgr_atomicity(config):
assert len(await config.foo()) == 15 assert len(await config.foo()) == 15
@pytest.mark.asyncio
async def test_set_with_partial_primary_keys(config): async def test_set_with_partial_primary_keys(config):
config.init_custom("CUSTOM", 3) config.init_custom("CUSTOM", 3)
await config.custom("CUSTOM", "1").set({"11": {"111": {"foo": "bar"}}}) 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" assert await config.custom("CUSTOM", "2", "33", "222").foo() == "biz"
@pytest.mark.asyncio
async def test_raw_with_partial_primary_keys(config): async def test_raw_with_partial_primary_keys(config):
config.init_custom("CUSTOM", 1) config.init_custom("CUSTOM", 1)
await config.custom("CUSTOM").set_raw("primary_key", "identifier", value=True) 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.parametrize("pkeys, raw_args, result", PARAMS)
@pytest.mark.asyncio
async def test_config_custom_partial_pkeys_get(config, pkeys, raw_args, result): async def test_config_custom_partial_pkeys_get(config, pkeys, raw_args, result):
# setup # setup
config.init_custom("TEST", 3) 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.parametrize("pkeys, raw_args, result", PARAMS)
@pytest.mark.asyncio
async def test_config_custom_partial_pkeys_set(config, pkeys, raw_args, result): async def test_config_custom_partial_pkeys_set(config, pkeys, raw_args, result):
# setup # setup
config.init_custom("TEST", 3) config.init_custom("TEST", 3)

View File

@ -1,6 +1,5 @@
import pytest import pytest
@pytest.mark.asyncio
async def test_can_init_bot(red): async def test_can_init_bot(red):
assert red is not None assert red is not None

View File

@ -15,7 +15,6 @@ def test_deduplicate_iterables():
assert deduplicate_iterables(*inputs) == expected assert deduplicate_iterables(*inputs) == expected
@pytest.mark.asyncio
async def test_bounded_gather(): async def test_bounded_gather():
status = [0, 0] # num_running, max_running status = [0, 0] # num_running, max_running
@ -52,7 +51,6 @@ async def test_bounded_gather():
assert num_fail == num_failed assert num_fail == num_failed
@pytest.mark.asyncio
async def test_bounded_gather_iter(): async def test_bounded_gather_iter():
status = [0, 0] # num_running, max_running 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.skip(reason="spams logs with pending task warnings")
@pytest.mark.asyncio
async def test_bounded_gather_iter_cancel(): async def test_bounded_gather_iter_cancel():
status = [0, 0, 0] # num_running, max_running, num_ran status = [0, 0, 0] # num_running, max_running, num_ran

View File

@ -73,7 +73,7 @@ def test_python_version_has_lower_bound():
@pytest.mark.skipif( @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.", reason="Testing on yet to be supported Python version.",
) )
def test_python_version_has_upper_bound(): def test_python_version_has_upper_bound():

View File

@ -1,2 +1,2 @@
tox<4 tox
-e .[dev] -e .[dev]

11
tox.ini
View File

@ -7,14 +7,15 @@
envlist = envlist =
py38 py38
py39 py39
py310
py311
docs docs
style style
skip_missing_interpreters = True skip_missing_interpreters = True
isolated_build = True
[testenv] [testenv]
description = Run tests and basic automatic issue checking. description = Run tests and basic automatic issue checking.
whitelist_externals = allowlist_externals =
pytest pytest
pylint pylint
extras = test extras = test
@ -27,7 +28,7 @@ commands =
[testenv:postgres] [testenv:postgres]
description = Run pytest with PostgreSQL backend description = Run pytest with PostgreSQL backend
whitelist_externals = allowlist_externals =
pytest pytest
extras = test, postgres extras = test, postgres
setenv = setenv =
@ -46,7 +47,7 @@ commands =
[testenv:docs] [testenv:docs]
description = Attempt to build docs with sphinx-build description = Attempt to build docs with sphinx-build
whitelist_externals = allowlist_externals =
sphinx-build sphinx-build
make make
setenv = setenv =
@ -61,7 +62,7 @@ commands =
[testenv:style] [testenv:style]
description = Stylecheck the code with black to see if anything needs changes. description = Stylecheck the code with black to see if anything needs changes.
whitelist_externals = allowlist_externals =
make make
setenv = setenv =
# This is just for Windows # This is just for Windows